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()。验证逻辑与业务逻辑存在矛盾。

此时需确认:

  1. 业务逻辑正确:应修改测试用例
  2. 测试用例正确:需修复代码缺陷

5. 总结

本文通过分析Mockito.verify()未触发的情况,揭示了正确使用模拟对象的要点。我们需要确保:

  • 正确注入和使用模拟对象
  • 测试用例与业务逻辑的一致性

最后,完整代码示例可在GitHub上找到。