You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Mockito:能否为被测类注入两个依赖的Spy?

能否为被测类注入两个依赖的Spy?

当然可以给你的被测类注入多个Spy!你遇到的调用顺序切换后测试失败的问题,大概率是因为其中一个Spy没有被正确绑定到DI容器,或者测试中验证的Spy实例和实际注入到被测类的不是同一个。

问题分析

从你的代码来看,两个依赖的Spy配置方式“完全一致”,但交换调用顺序后测试失败,这说明:

  • 其中一个Spy可能没有被真正注入到LinkHitCallbackEventHandler中,被测类实际调用的是真实对象而非Spy,导致verify断言失败。
  • 测试方法中用来验证的Spy实例,和DI容器中注入到被测类的Spy实例不是同一个(比如你在测试方法里重新创建了Spy,而非复用容器中的实例)。

解决方案

要确保两个Spy都被正确注入并能被验证,你需要保证:

  1. Spy实例在DI容器中正确绑定,且被测类注入的是Spy而非真实对象。
  2. 测试方法中用来verify的Spy,和容器中的是同一个实例。

下面是调整后的完整测试代码示例(基于JerseyTest + HK2绑定):

public class LinkHitCallbackEventHandlerTest extends JerseyTest {
    // 声明Spy为测试类成员变量,确保全局复用
    private CallbackInvocationBuilder callbackInvocationBuilderSpy;
    private CallbackLogBuilder callbackLogBuilderSpy;

    @Override
    protected Application configure() {
        // 初始化两个Spy实例
        callbackInvocationBuilderSpy = Mockito.spy(new CallbackInvocationBuilder());
        callbackLogBuilderSpy = Mockito.spy(new CallbackLogBuilder());

        return new ResourceConfig()
            .register(LinkHitCallbackEventHandler.class)
            .register(new AbstractBinder() {
                @Override
                protected void configure() {
                    // 将Spy绑定到对应接口/类,确保被测类注入的是Spy实例
                    bind(callbackInvocationBuilderSpy).to(CallbackInvocationBuilder.class);
                    bind(callbackLogBuilderSpy).to(CallbackLogBuilder.class);
                }
            });
    }

    @Test
    public void send_callback_after_event_is_published() {
        // 触发事件的请求
        target("/testY")
            .property("jersey.config.client.followRedirects", false)
            .request()
            .header("User-Agent", UserAgentMother.allowedUserAagent())
            .get();

        // 验证两个Spy的方法调用,顺序不影响单独的verify断言
        verify(callbackLogBuilderSpy).build(any(Entity.class));
        verify(callbackInvocationBuilderSpy).post(any(Entity.class));
    }
}

关键注意点

  • 不要在测试方法中重新创建Spy实例,必须复用configure()中初始化并绑定到容器的那个实例,否则verify的对象和被测类调用的对象不是同一个,断言必然失败。
  • 确保你的DI容器(Jersey默认用HK2)支持字段注入(你的被测类用了@Inject字段注入,HK2是支持的,但如果有构造函数的话,优先构造函数注入会更可靠)。
  • 如果需要验证调用顺序,可以用InOrder:
    InOrder inOrder = inOrder(callbackLogBuilderSpy, callbackInvocationBuilderSpy);
    inOrder.verify(callbackLogBuilderSpy).build(any(Entity.class));
    inOrder.verify(callbackInvocationBuilderSpy).post(any(Entity.class));
    

内容的提问来源于stack exchange,提问作者Marcin Zadworny

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.07 12:57:30