《Java单元测试实战》——编写方法:Java编程技巧之单元测试用例编写流程(15) https://developer.aliyun.com/article/1232403?groupCode=java
十一、 典型案例及解决方案
这里,只收集了几个经典案例,解决了特定环境下的特定问题。
1. 测试框架特性导致问题
在编写单元测试用例时,或多或少会遇到一些问题,大多数是由于对测试框架特性不熟悉导致,比如:
• Mockito不支持对静态方法、构造方法、final方法、私有方法的模拟;
• Mockito的any相关的参数匹配方法并不支持可空参数和空参数;
• 采用Mockito的参数匹配方法时,其它参数不能直接用常量或变量,必须使用Mockito的eq方法;
• 使用when-then语句模拟Spy对象方法会先执行真实方法,应该使用do-when语句;
• PowerMock对静态方法、构造方法、final方法、私有方法的模拟需要把对应的类添加到@PrepareForTest注解中;
• PowerMock模拟JDK的静态方法、构造方法、final方法、私有方法时,需要把使用这些方法的类加入到@PrepareForTest注解中,从而导致单元测试覆盖率不被统计;
• PowerMock使用自定义的类加载器来加载类,可能导致系统类加载器认为有类型转换问题;需要加上@PowerMockIgnore({"javax.crypto.*"})注解,来告诉PowerMock这个包不要用PowerMock的类加载器加载,需要采用系统类加载器来加载。
对于这些问题,可以根据提示信息查阅相关资料解决,这里就不再累述了。
2. 捕获参数值已变更问题
在编写单元测试用例时,通常采用ArgumentCaptor进行参数捕获,然后对参数对象值进行验证。如果参数对象值没有变更,这个步骤就没有任何问题。但是,如果参数对象值在后续流程中发生变更,就会导致验证参数值失败。
原始代码:
测试用例:
问题现象:
执行单元测试用例失败,抛出以下异常信息:
问题原因:
由于参数dataList在调用dataStorage.test方法后,都被主动调用dataList.clear方法进行清空。由于ArgumentCaptor捕获的是对象引用,所以最后捕获到了同一个空列表。
解决方案:
可以在模拟依赖方法dataStorage.test时,保存传入参数的当前值进行验证。代码如下:
3. 模拟Lombok的log对象问题
Lombok的@Slf4j注解,广泛地应用于Java项目中。在某些代码分支里,可能只有log记录日志的操作,为了验证这个分支逻辑被正确执行,需要在单元测试用例中对log记录日志的操作进行验证。
原始方法:
测试用例:
问题现象:
执行单元测试用例失败,抛出以下异常信息:
原因分析:
经过调式跟踪,发现ExampleService中的log对象并没有被注入。通过编译发现,Lombok的@Slf4j注解在ExampleService类中生成了一个静态常量log,而@InjectMocks注解并不支持静态常量的注入。
解决方案:
采用作者实现的FieldHelper.setStaticFinalField方法,可以实现对静态常量的注入模拟对象。
《Java单元测试实战》——编写方法:Java编程技巧之单元测试用例编写流程(17 https://developer.aliyun.com/article/1232401?groupCode=java