《Java单元测试实战》——编写方法:Java编程技巧之单元测试用例编写流程(2)

简介: 《Java单元测试实战》——编写方法:Java编程技巧之单元测试用例编写流程(2)

《Java单元测试实战》——编写方法:Java编程技巧之单元测试用例编写流程(1) https://developer.aliyun.com/article/1232420?groupCode=java



3) 一个有依赖的单元测试

 

一个有依赖的单元测试,需要四大步骤:

 

定义对象:定义测试对象、模拟依赖对象、注入依赖对象;

模拟方法:模拟参数或返回值、模拟依赖方法;

调用方法:传入参数对象、调用测试方法、验证返回值或异常;

验证方法:验证依赖方法、验证方法参数、验证依赖对象。

 

案例代码


/**
 * 用户服务类
 */
@Service
public class UserService {
    /** 定义依赖对象 */
    /** 用户DAO */
    @Autowired
    private UserDAO userDAO;
    /** 标识生成器 */
    @Autowired
    private IdGenerator idGenerator;
    /** 定义依赖参数 */
    /** 可以修改 */
    @Value("${userService.canModify}")
    private Boolean canModify;
    /**
     * 保存用户
     * 
     * @param userSave 用户保存
     * @return 用户标识
     */
    public Long saveUser(UserVO userSave) {
        // 获取用户标识
        Long userId = userDAO.getIdByName(userSave.getName());
        // 根据存在处理
        // 根据存在处理: 不存在则创建
        if (Objects.isNull(userId)) {
            userId = idGenerator.next();
            UserDO userCreate = new UserDO();
            userCreate.setId(userId);
            userCreate.setName(userSave.getName());
            userCreate.setDescription(userSave.getDescription());
            userDAO.create(userCreate);
        }
        // 根据存在处理: 已存在可修改
        else if (Boolean.TRUE.equals(canModify)) {
            UserDO userModify = new UserDO();
            userModify.setId(userId);
            userModify.setName(userSave.getName());
            userModify.setDescription(userSave.getDescription());
            userDAO.modify(userModify);
        }
        // 根据存在处理: 已存在禁修改
        else {
            throw new UnsupportedOperationException("不支持修改");
        }
        // 返回用户标识
        return userId;
    }
}

测试用例

 

/**
 * 用户服务测试类
 */
@RunWith(MockitoJUnitRunner.class)
public class UserServiceTest {
    /** 定义静态常量 */
    /** 资源路径 */
    private static final String RESOURCE_PATH = "testUserService/";
    /** 模拟依赖对象 */
    /** 用户DAO */
    @Mock
    private UserDAO userDAO;
    /** 标识生成器 */
    @Mock
    private IdGenerator idGenerator;
    /** 定义测试对象 */
    /** 用户服务 */
    @InjectMocks
    private UserService userService;
    /**
     * 在测试之前
     */
    @Before
    public void beforeTest() {
        Whitebox.setInternalState(userService, "canModify", Boolean.TRUE);
    }
    /**
     * 测试: 保存用户-创建
     */
    @Test
    public void testSaveUserWithCreate() {
        // 模拟依赖方法
        // 模拟依赖方法: userDAO.getIdByName
        Mockito.doReturn(null).when(userDAO).getIdByName(Mockito.anyString());
        // 模拟依赖方法: idGenerator.next
        Long userId = 123L;
        Mockito.doReturn(userId).when(idGenerator).next();
        // 调用测试方法
        String path = RESOURCE_PATH + "testSaveUserWithCreate/";
        String text = ResourceHelper.getResourceAsString(getClass(), path + "userSave.json");
        UserSaveVO userSave = JSON.parseObject(text, UserSaveVO.class);
        Assert.assertEquals("用户标识不一致", userId, userService.saveUser(userSave));
        // 验证依赖方法
        // 验证依赖方法: userDAO.getIdByName
        Mockito.verify(userDAO).getIdByName(userSave.getName());
        // 验证依赖方法: idGenerator.next
        Mockito.verify(idGenerator).next();
        // 验证依赖方法: userDAO.create
        ArgumentCaptor<UserDO> userCreateCaptor = ArgumentCaptor.forClass(UserDO.class);
        Mockito.verify(userDAO).create(userCreateCaptor.capture());
        text = ResourceHelper.getResourceAsString(getClass(), path + "userCreate.json");
        Assert.assertEquals("用户创建不一致", text, JSON.toJSONString(userCreateCaptor.getValue()));
        // 验证依赖对象
        Mockito.verifyNoMoreInteractions(userDAO, idGenerator);
    }
    /**
     * 测试: 保存用户-修改
     */
    @Test
    public void testSaveUserWithModify() {
        // 模拟依赖方法
        // 模拟依赖方法: userDAO.getIdByName
        Long userId = 123L;
        Mockito.doReturn(userId).when(userDAO).getIdByName(Mockito.anyString());
        // 调用测试方法
        String path = RESOURCE_PATH + "testSaveUserWithModify/";
        String text = ResourceHelper.getResourceAsString(getClass(), path + "userSave.json");
        UserSaveVO userSave = JSON.parseObject(text, UserSaveVO.class);
        Assert.assertEquals("用户标识不一致", userId, userService.saveUser(userSave));
        // 验证依赖方法
        // 验证依赖方法: userDAO.getIdByName
        Mockito.verify(userDAO).getIdByName(userSave.getName());
        // 验证依赖方法: userDAO.modify
        ArgumentCaptor<UserDO> userModifyCaptor = ArgumentCaptor.forClass(UserDO.class);
        Mockito.verify(userDAO).modify(userModifyCaptor.capture());
        text = ResourceHelper.getResourceAsString(getClass(), path + "userModify.json");
        Assert.assertEquals("用户修改不一致", text, JSON.toJSONString(userModifyCaptor.getValue()));
        // 验证依赖对象
        Mockito.verifyNoMoreInteractions(userDAO, idGenerator);
    }
    /**
     * 测试: 保存用户-异常
     */
    @Test
    public void testSaveUserWithException() {
        // 注入依赖对象
        Whitebox.setInternalState(userService, "canModify", Boolean.FALSE);
        // 模拟依赖方法
        // 模拟依赖方法: userDAO.getIdByName
        Mockito.doReturn(123L).when(userDAO).getIdByName(Mockito.anyString());
        // 调用测试方法
        String path = RESOURCE_PATH + "testSaveUserWithException/";
        String text = ResourceHelper.getResourceAsString(getClass(), path + "userSave.json");
        UserSaveVO userSave = JSON.parseObject(text, UserSaveVO.class);
        UnsupportedOperationException exception = Assert.assertThrows("异常类型不一致", UnsupportedOperationException.class,
            () -> userService.saveUser(userSave));
        Assert.assertEquals("异常消息不一致", "不支持修改", exception.getMessage());
        // 验证依赖方法
        // 验证依赖方法: userDAO.getIdByName
        Mockito.verify(userDAO).getIdByName(userSave.getName());
        // 验证依赖对象
        Mockito.verifyNoMoreInteractions(userDAO, idGenerator);
    }
}
其中,加载的JSON资源文件内容如下:
userSave.json:
userCreate.json:
userModify.json:

通过执行以上测试用例,可以看到对源代码进行了100%的行覆盖。




《Java单元测试实战》——编写方法:Java编程技巧之单元测试用例编写流程(3) https://developer.aliyun.com/article/1232418?groupCode=java

 

相关文章
|
XML Java Maven
在 Cucumber 测试中自动将 Cucumber 数据表映射到 Java 对象
在 Cucumber 测试中自动将 Cucumber 数据表映射到 Java 对象
399 7
|
XML Java 测试技术
Selenium WebDriver自动化测试(基础篇):不得不掌握的Java基础
关于Selenium WebDriver自动化测试的Java基础篇,涵盖了Java的变量、数据类型、字符串操作、运算符、流程控制、面向对象编程、关键字用法、权限修饰符、异常处理和IO流等基础知识点,为进行自动化测试提供了必要的Java语言基础。
430 1
|
Java 测试技术 API
Java 新手入门:Java单元测试利器,Mock详解
Java 新手入门:Java单元测试利器,Mock详解
1186 1
|
算法 Java 测试技术
数据结构 —— Java自定义代码实现顺序表,包含测试用例以及ArrayList的使用以及相关算法题
文章详细介绍了如何用Java自定义实现一个顺序表类,包括插入、删除、获取数据元素、求数据个数等功能,并对顺序表进行了测试,最后还提及了Java中自带的顺序表实现类ArrayList。
507 0
|
IDE Java 测试技术
Java面试题:什么是Java中的单元测试以及如何编写单元测试?
Java面试题:什么是Java中的单元测试以及如何编写单元测试?
635 1
|
JSON 测试技术 Go
Go 单元测试完全指南(一)- 基本测试流程
Go 单元测试完全指南(一)- 基本测试流程
271 0
|
Java 测试技术
Java SpringBoot Test 单元测试中包括多线程时,没跑完就结束了
Java SpringBoot Test 单元测试中包括多线程时,没跑完就结束了
440 0
|
Java 测试技术 API
深入理解单元测试:JUnit框架在Java中的应用
【8月更文挑战第3天】本文将引导读者通过JUnit框架的镜头,探索单元测试的奥秘。我们将一起揭开单元测试的神秘面纱,了解其在软件开发中的关键作用,并具体学习如何在Java项目中应用JUnit进行有效的单元测试。文章不仅会涉及理论概念,还将通过具体的代码示例,展示如何编写和运行单元测试,以确保软件质量。让我们开始吧,一起踏上这段提升代码质量和开发效率的旅程。
209 0
|
Java 数据库 Spring
Java编程问题之在测试中使用CGLIB创建代理类如何解决
Java编程问题之在测试中使用CGLIB创建代理类如何解决
275 0
|
数据可视化 前端开发 测试技术
接口测试新选择:Postman替代方案全解析
在软件开发中,接口测试工具至关重要。Postman长期占据主导地位,但随着国产工具的崛起,越来越多开发者转向更适合中国市场的替代方案——Apifox。它不仅支持中英文切换、完全免费不限人数,还具备强大的可视化操作、自动生成文档和API调试功能,极大简化了开发流程。