
在 Mockito 中,若需拦截被测类自身的方法调用(如 mainMethod 内部调用的 methodtWhichNeedMock),不能使用 @InjectMocks,而应改用 @Spy 创建部分模拟对象,从而实现对指定方法的 stub 而保留其余逻辑真实执行。
在 mockito 中,若需拦截被测类自身的方法调用(如 `mainmethod` 内部调用的 `methodtwhichneedmock`),不能使用 `@injectmocks`,而应改用 `@spy` 创建部分模拟对象,从而实现对指定方法的 stub 而保留其余逻辑真实执行。
在编写单元测试时,常遇到一种典型场景:被测类(如 Test)的某个公共方法(如 mainMethod())内部调用了该类自身的另一个方法(如 methodtWhichNeedMock()),而我们希望在测试中跳过该内部方法的真实逻辑,仅返回预设值——即对该类自身方法进行“部分模拟”(partial mocking)。此时,@InjectMocks 无法满足需求,因为它仅用于注入依赖,不会对被测对象本身做任何模拟处理;所有方法调用仍会执行原始实现。
正确做法是使用 @Spy 注解创建一个真实对象的代理(spy)。@Spy 会实例化真实的 Test 对象,并允许你对其中任意方法进行 stub(例如 when(...).thenReturn(...)),而未 stub 的其他方法则照常执行真实逻辑。
以下是修正后的完整测试示例:
@ExtendWith(MockitoExtension.class)
class TestClass {
@Spy
Test service; // ✅ 使用 @Spy,而非 @InjectMocks
@Test
void mainMethod() {
// ✅ stub 自身方法:当 methodtWhichNeedMock("s1", "s2") 被调用时,返回 "new String"
when(service.methodtWhichNeedMock("s1", "s2")).thenReturn("new String");
// ✅ 此时 service.mainMethod() 将调用真实 mainMethod,
// 但其内部对 methodtWhichNeedMock 的调用会被 stub 拦截
String result = service.mainMethod();
assertEquals("new String", result);
}
}
⚠️ 注意事项:
- 方法签名必须严格匹配:
when(...)中传入的参数需与实际调用时一致(包括类型和值)。若存在动态参数(如任意字符串),可使用anyString()等匹配器,但需确保所有参数都使用匹配器(或全为具体值),避免混合使用。 - 拼写错误会导致 stub 失效(如原问题中
methdotWhichNeedMock和methodtWhichNeedMock不一致),务必核对方法名、参数类型及大小写。 -
@Spy对象默认调用真实方法,因此无需额外配置即可保障mainMethod()的主体逻辑正常运行——这正是部分模拟的核心价值。 - 若需模拟
private方法或更复杂的内部行为,@Spy无能为力,此时应考虑重构(如提取为依赖接口并用@Mock注入),以提升可测性。
总结:当目标是“拦截被测类自身方法调用”时,请坚定选择 @Spy;它轻量、语义清晰,是实现可控部分模拟的标准实践。










