1. 概述
在使用 Mockito 进行单元测试时,我们可能会遇到如下异常提示:
Wanted but not invoked:
// class name and location
Actually, there were zero interactions with this mock.
本文将深入解析这个常见错误,并提供解决方案。
2. 创建示例
首先,我们创建一个稍后将要模拟的Helper类。 其 getBaeldungString()
方法始终返回固定字符串 "Baeldung"
class Helper {
String getBaeldungString() {
return "Baeldung";
}
}
现在,我们创建主类。该类包含一个 Helper
实例成员。我们的测试目标是要模拟这个Helper实例:
class Main {
Helper helper = new Helper();
String methodUnderTest(int i) {
if (i > 5) {
return helper.getBaeldungString();
}
return "Hello";
}
}
此外,我们定义了一个方法,它接受一个 Integer 参数并返回:
- 如果 Integer 大于5,调用 getBaeldunString()
- 如果 Integer 小于或等于5,返回一个常量
3. 案例一,实际方法被调用而非模拟
编写单元测试时,使用 @Mock 注解模拟对象,并通过 openMocks() 启用Mockito注解支持
class MainUnitTest {
@Mock
Helper helper;
Main main = new Main();
@BeforeEach
void setUp() {
MockitoAnnotations.openMocks(this);
}
@Test
void givenValueUpperThan5_WhenMethodUnderTest_ThenDelegatesToHelperClass() {
main.methodUnderTest(7);
Mockito.verify(helper)
.getBaeldungString();
}
}
执行测试后将抛出异常。
Wanted but not invoked:
helper.getBaeldungString();
-> at com.baeldung.wantedbutnotinvocked.Helper.getBaeldungString(Helper.java:6)
Actually, there were zero interactions with this mock.
根本原因是 Main 类通过构造函数直接实例化了Helper对象,导致实际调用的是真实对象而非模拟对象。 解决方法是在Main实例上添加 @InjectMocks 注解:
@InjectMocks
Main main = new Main();
注意:若在测试方法中重新实例化Helper对象,同样会导致mock失效:
String methodUnderTest(int i) {
helper = new Helper();
if (i > 5) {
return helper.getBaeldungString();
}
return "Hello";
}
关键注意点:
- 1.正确初始化并注入mock对象
- 2.避免在测试流程中覆盖模拟对象
4. 案例二,方法未被实际调用
现在我们将编写一个新的单元测试,验证传入参数3时是否调用 getBaeldungString()
@Test
void givenValueLowerThan5_WhenMethodUnderTest_ThenDelegatesToGetBaeldungString() {
main.methodUnderTest(3);
Mockito.verify(helper)
.getBaeldungString();
}
再次运行测试:
Wanted but not invoked:
helper.getBaeldungString();
-> at com.baeldung.wantedbutnotinvocked.Helper.getBaeldungString(Helper.java:6)
Actually, there were zero interactions with this mock.
运行测试时出现相同错误,因为参数3小于5时,方法直接返回"Hello",不是委托给getBaeldungString()。验证逻辑与业务逻辑存在矛盾。
此时需确认:
- 业务逻辑正确:应修改测试用例
- 测试用例正确:需修复代码缺陷
5. 总结
本文通过分析Mockito.verify()未触发的情况,揭示了正确使用模拟对象的要点。我们需要确保:
- 正确注入和使用模拟对象
- 测试用例与业务逻辑的一致性
最后,完整代码示例可在GitHub上找到。