单元测试可以提高测试开发的效率,减少代码错误率,提高代码健壮性,提高代码质量。在 Spring 框架中常用的两种测试框架:`PowerMockRunner` 和 `SpringRunner` 两个单元测试,鉴于 `SpringRunner` 启动的一系列依赖和数据连接的问题,推荐使用 `PowerMockRunner`,这样能有效的提高测试的效率,并且其提供的 API 能覆盖的场景广泛,使用方便,可谓是 Java 单元测试之模拟利器。 ## 1. PowerMock 是什么? `PowerMock` 是一个 Java 模拟框架,可用于解决通常认为很难甚至无法测试的测试问题。使用 `PowerMock`,可以模拟静态方法,删除静态初始化程序,允许模拟而不依赖于注入,等等。`PowerMock` 通过在执行测试时在运行时修改字节码来完成这些技巧。`PowerMock` 还包含一些实用程序,可让您更轻松地访问对象的内部状态。 举个例子,你在使用 `Junit` 进行单元测试时,并不想让测试数据进入数据库,怎么办?这个时候就可以使用 `PowerMock`,拦截数据库操作,并模拟返回参数。 ## 2. PowerMock 包引入 ```xml org.powermock powermock-core 2.0.2 test org.mockito mockito-core 2.23.0 org.powermock powermock-module-junit4 2.0.4 test org.powermock powermock-api-mockito2 2.0.2 test com.github.jsonzou jmockdata 4.3.0 ``` ## 3. 重要注解说明 ```java @RunWith(PowerMockRunner.class) // 告诉JUnit使用PowerMockRunner进行测试 @PrepareForTest({RandomUtil.class}) // 所有需要测试的类列在此处,适用于模拟final类或有final, private, static, native方法的类 @PowerMockIgnore("javax.management.*") //为了解决使用powermock后,提示classloader错误 ``` ## 4. 使用示例 ### 4.1 模拟接口返回 首先对接口进行 mock,然后录制相关行为 ```java InterfaceToMock mock = Powermockito.mock(InterfaceToMock.class) Powermockito.when(mock.method(Params…)).thenReturn(value) Powermockito.when(mock.method(Params..)).thenThrow(Exception) ``` ### 4.2 设置对象的 private 属性 需要使用 `Whitebox` 向 class 或者对象中赋值。 如我们已经对接口尽心了 mock,现在需要将此 mock 加入到对象中,可以采用如下方法: ```java Whitebox.setInternalState(Object object, String fieldname, Object… value); ``` 其中 object 为需要设置属性的静态类或对象。 ### 4.3 模拟构造函数 对于模拟构造函数,也即当出现 `new InstanceClass()` 时可以将此构造函数拦截并替换结果为我们需要的 mock 对象。 注意:使用时需要加入标记: ```java @RunWith(PowerMockRunner.class) @PrepareForTest({ InstanceClass.class }) @PowerMockIgnore("javax.management.\*") Powermockito.whenNew(InstanceClass.class).thenReturn(Object value) ``` ##### 4.4 模拟静态方法 模拟静态方法类似于模拟构造函数,也需要加入注释标记。 ```java @RunWith(PowerMockRunner.class) @PrepareForTest({ StaticClassToMock.class }) @PowerMockIgnore("javax.management.\*") Powermockito.mockStatic(StaticClassToMock.class); Powermockito.when(StaticClassToMock.method(Object.. params)).thenReturn(Object value) ``` ##### 4.5 模拟 final 方法 Final 方法的模拟类似于模拟静态方法。 ```java @RunWith(PowerMockRunner.class) @PrepareForTest({ FinalClassToMock.class }) @PowerMockIgnore("javax.management.\*") Powermockito.mockStatic(FinalClassToMock.class); Powermockito.when(StaticClassToMock.method(Object.. params)).thenReturn(Object value) ``` ### 4.6 模拟静态类 模拟静态类类似于模拟静态方法。 ### 4.7 使用 spy 方法避免执行被测类中的成员函数 如被测试类为:TargetClass,想要屏蔽的方法为 targetMethod. ```java 1) PowerMockito.spy(TargetClass.class); 2) Powemockito.when(TargetClass.targetMethod()).doReturn() 3) 注意加入 @RunWith(PowerMockRunner.class) @PrepareForTest(DisplayMoRelationBuilder.class) @PowerMockIgnore("javax.management.*") ``` ### 4.8 参数匹配器 有时我们在处理 `doMethod(Param param)` 时,不想进行精确匹配,这时可以使用 `Mockito` 提供的模糊匹配方式。 如:`Mockito.anyInt()`,`Mockito.anyString()` ### 4.9 处理 public void 型的静态方法 ```java Powermockito.doNothing.when(T class2mock, String method, … params> ``` ## 5. 单元测试用例可选清单 输入数据验证:这些检查通常可以对输入到应用程序系统中的数据采用。 - 必传项测试 - 唯一字段值测试 - 空值测试 - 字段只接受允许的字符 - 负值测试 - 字段限于字段长度规范 - 不可能的值 - 垃圾值测试 - 检查字段之间的依赖性 - 等效类划分和边界条件测试 - 错误和异常处理测试单元测试可以提高测试开发的效率,减少代码错误率,提高代码健壮性,提高代码质量。在 Spring 框架中常用的两种测试框架:PowerMockRunner 和 SpringRunner 两个单元测试,鉴于 SpringRunner 启动的一系列依赖和数据连接的问题,推荐使用 PowerMockRunner,这样能有效的提高测试的效率,并且其提供的 API 能覆盖的场景广泛,使用方便,可谓是 Java 单元测试之模拟利器。