Java 单元测试及常用语句

1 前言 
编写 JAVA 单元测试用例 , 即把一段复杂的代码拆解成一系列简单的单元测试用例 , 并且无需启动服务 , 在短时间内测试代码中的处理逻辑 。写好 Java 单元测试用例 , 其实就是把 “复杂问题简单化 , 建单问题深入化 “ 。在编写的过程中 ,  我们也可以对自己的代码进行一个二次检查 。
以下是我总结的一些编写单元测试的好处:
1. 测试代码逻辑时 , 不需要启动整个应用 。
2. 单元测试可以覆盖边界值
3. 提高原有代码的复用
4. 可以有效避免代码改动后 , 对原有逻辑的潜在影响
2 准备环境Mockito 是目前最普遍的单元测试模拟框架 。Mockito 可以模拟应用中依赖的复杂对象 , 从而把测试对象和依赖对象隔离开 。PowerMock 为 Mockito 提供了扩展功能 。为模拟静态方法 , final 类 , 和私有方法等 。我们选择使用以 Mockito 为主 , PowerMock 为辅的框架来做单元测试 。
2.1 引入 Mockito 和 PowerMock 包 , 在 pom.xml 文件中加入以下依赖:
<properties>
<powermock.version>2.0.9</powermock.version>
</properties>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-core</artifactId>
<version>${powermock.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-mockito2</artifactId>
<version>${powermock.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-junit4</artifactId>
<version>${powermock.version}</version>
<scope>test</scope>
PowerMock 目前最新版本为 2.0.9【PowerMock 链接】由于 PowerMock 包中已经包含了对应的 Mockito 和 JUnit 包 , 所以无需再单独引入 。
3 一些常用的 mock 语句3.1 模拟指定类的对象实例 , 用于模拟依赖对象(类成员)
在 Spring 中 , 这些成员对象通过 @Autowire , @Resource , @Value 等方式注入 , 可能涉及到环境配置或者依赖第三方接口 。在单元测试中 , 不是我们关注的点 , 所以可以用 mock 模拟
//方法一
Mockito.mock(OrderInfo.class);
//方法二
@Mock
private OrderInfo orderInfo;
@Before
public void setUp(){
MockitoAnnotations.initMocks(this);
}
3.2 定义被测试对象
把被测试服务类进行实例化
@InjectMocks
private OrderServiceImpl orderService;
3.3 模拟枚举类型 / 静态方法
需要把对应的模拟类放在 @PrepareForTest 中
//必须添加@RunWith和@PrepareForTest在类前
@RunWith(PowerMockRunner.class)
@PrepareForTest(OrderTypeEnum.class)
//在@Before中添加枚举mock
@Before
public void beforeTest() {
mockStatic(OrderTypeEnum.class);
}
3.4 模拟依赖方法
在模拟完依赖的参数和返回值后 , 可以利用 Mockito 功能 , 进行依赖方法的模拟 。如果模拟对象还有方法调用 , 则需要模拟这些依赖对象的方法 。
/***
when.thenReturn 和 doReturn.when是两种实现方式
只有在使用@Spy时才会有区别
参考链接:https://www.imooc.com/wenda/detAIl/594190#id_653606
***/
//模拟枚举的方法调用
when(OrderTypeEnum.getByValue(anyInt())).thenReturn(100);
//模拟依赖对象的依赖方法调用
doReturn(resultInfoDTO).when(orderInfoService).getLastOrderInfo(orderInfoDTO);
3.5 模拟构造方法
PowerMock 提供了对构造方法的模拟 , 但是需要把构造方法的类放在 @PrepareForTest 中
//必须在@PrepareForTest中添加对应类
@PrepareForTest({OrderTypeEnum.class, OrderServiceImpl.class})
whenNew(OrderInfoDTO.class).withNoArguments().thenReturn(orderInfoDTO);
3.6 验证方法调用次数
被测方法调用后 , 一些方法会出现调用多次或根据不同条件进行不同次数的调用 。此时 , 可以根据验证方法调用次数 , 确定代码的有效性
verify(orderInfoService,times(1)).getLastOrderInfo(orderInfoDTO);
3.7 验证返回值
对于方法调用后的出参 , 我们会有一定的预期 。所以 , 可以根据校验返回值是否符合预期 , 确保返回值的正确性


推荐阅读