接上篇:https://developer.aliyun.com/article/1227514?spm=a2c6h.13148508.setting.21.34364f0esCxN3Z
十、 验证依赖对象
1. 验证模拟对象没有任何方法调用
Mockito提供了verifyNoInteractions方法,可以验证模拟对象在被测试方法中没有任何调用。
2. 验证模拟对象没有更多方法调用
Mockito提供了verifyNoMoreInteractions方法,在验证模拟对象所有方法调用后使用,可以验证模拟对象所有方法调用是否都得到验证。如果模拟对象存在任何未验证的方法调用,就会抛出NoInteractionsWanted异常。
备注
Mockito的verifyZeroInteractions方法与verifyNoMoreInteractions方法功能相同,但是目前前者已经被废弃。
3. 清除模拟对象所有方法调用标记
在编写单元测试用例时,为了减少单元测试用例数和代码量,可以把多组参数定义在同一个单元测试用例中,然后用for循环依次执行每一组参数的被测方法调用。为了避免上一次测试的方法调用影响下一次测试的方法调用验证,最好使用Mockito提供clearInvocations方法清除上一次的方法调用。
十一、 典型案例及解决方案
这里,只收集了几个经典案例,解决了特定环境下的特定问题。
1. 测试框架特性导致问题
在编写单元测试用例时,或多或少会遇到一些问题,大多数是由于对测试框架特性不熟悉导致,比如:
• Mockito不支持对静态方法、构造方法、final方法、私有方法的模拟;
• Mockito的any相关的参数匹配方法并不支持可空参数和空参数;
• 如果为Mock方法或Mock方法参数不匹配时,会返回默认值(基础类型为0,对象类型为null);
• 采用Mockito的参数匹配方法或Argument的captor方法时,其它参数不能直接用常量或变量,必须使用Mockito的eq方法包装;
• 使用when-then语句模拟Spy对象方法会先执行真实方法,应该使用do-when语句;
• PowerMock对静态方法、构造方法、final方法、私有方法的模拟需要把对应的类添加到@PrepareForTest注解中;
• PowerMock模拟JDK的静态方法、构造方法、final方法、私有方法时,需要把使用这些方法的类加入到@PrepareForTest注解中,从而导致单元测试覆盖率不被统计;
• PowerMock使用自定义的类加载器来加载类,可能导致系统类加载器认为有类型转换问题;需要加上@PowerMockIgnore({"javax.crypto.*"})注解,来告诉PowerMock这个包不要用PowerMock的类加载器加载,需要采用系统类加载器来加载;
• 如果遇到Mock对象静态常量初始化失败,可以利用注解@SuppressStaticInitializationFor抑制静态常量初始化。
对于这些问题,可以根据提示信息查阅相关资料解决,这里就不再累述了。
2. 捕获参数值已变更问题
在编写单元测试用例时,通常采用ArgumentCaptor进行参数捕获,然后对参数对象值进行验证。如果参数对象值没有变更,这个步骤就没有任何问题。但是,如果参数对象值在后续流程中发生变更,就会导致验证参数值失败。
1) 原始代码
2) 测试用例
3) 问题现象
执行单元测试用例失败,抛出以下异常信息:
4) 问题原因
由于参数dataList在调用dataStorage.test方法后,都被主动调用dataList.clear方法进行清空。由于ArgumentCaptor捕获的是对象引用,所以最后捕获到了同一个空列表。
5) 解决方案
可以在模拟依赖方法dataStorage.test时,保存传入参数的当前值进行验证。代码如下:
接下篇:https://developer.aliyun.com/article/1227512?groupCode=java