在 Guice 中重写绑定

2022-08-31 07:25:56

我刚刚开始玩Guice,我能想到的一个用例是,在测试中我只想覆盖单个绑定。我想我想使用其余的生产级绑定来确保所有内容都设置正确并避免重复。

所以想象我有以下模块

public class ProductionModule implements Module {
    public void configure(Binder binder) {
        binder.bind(InterfaceA.class).to(ConcreteA.class);
        binder.bind(InterfaceB.class).to(ConcreteB.class);
        binder.bind(InterfaceC.class).to(ConcreteC.class);
    }
}

在我的测试中,我只想覆盖InterfaceC,同时保持InterfaceA和InterfaceB不变,所以我想要这样的东西:

Module testModule = new Module() {
    public void configure(Binder binder) {
        binder.bind(InterfaceC.class).to(MockC.class);
    }
};
Guice.createInjector(new ProductionModule(), testModule);

我还尝试了以下方法,但没有运气:

Module testModule = new ProductionModule() {
    public void configure(Binder binder) {
        super.configure(binder);
        binder.bind(InterfaceC.class).to(MockC.class);
    }
};
Guice.createInjector(testModule);

有谁知道是否有可能做我想做的事,或者我完全吠错了树??

--- 跟进:如果我在接口上使用@ImplementedBy标记,然后在测试用例中提供绑定,那么它似乎可以实现我想要的,当接口和实现之间存在1-1映射时,它工作得很好。

此外,在与同事讨论这个问题之后,我们似乎会走上重写整个模块并确保正确定义模块的道路。这似乎可能会导致一个问题,尽管绑定在模块中放错了位置并且需要移动,因此可能会破坏测试负载,因为绑定可能不再可用于重写。


答案 1

这可能不是你要找的答案,但是如果你正在编写单元测试,你可能不应该使用注入器,而应该手动注入模拟或假对象。

另一方面,如果您确实要替换单个绑定,则可以使用:Modules.override(..)

public class ProductionModule implements Module {
    public void configure(Binder binder) {
        binder.bind(InterfaceA.class).to(ConcreteA.class);
        binder.bind(InterfaceB.class).to(ConcreteB.class);
        binder.bind(InterfaceC.class).to(ConcreteC.class);
    }
}
public class TestModule implements Module {
    public void configure(Binder binder) {
        binder.bind(InterfaceC.class).to(MockC.class);
    }
}
Guice.createInjector(Modules.override(new ProductionModule()).with(new TestModule()));

有关详细信息,请参阅模块文档

但是正如 javadoc for 所建议的那样,您应该以不需要覆盖绑定的方式设计模块。在您给出的示例中,您可以通过将 的绑定移动到单独的模块来实现此目的。Modules.overrides(..)InterfaceC


答案 2

为什么不使用继承?可以在方法中重写特定绑定,而将共享实现保留在方法中。overrideMeconfigure

public class DevModule implements Module {
    public void configure(Binder binder) {
        binder.bind(InterfaceA.class).to(TestDevImplA.class);
        overrideMe(binder);
    }

    protected void overrideMe(Binder binder){
        binder.bind(InterfaceC.class).to(ConcreteC.class);
    }
};

public class TestModule extends DevModule {
    @Override
    public void overrideMe(Binder binder) {
        binder.bind(InterfaceC.class).to(MockC.class);
    }
}

最后,以这种方式创建您的喷油器:

Guice.createInjector(new TestModule());

推荐