Java 通过侦听器、侦听器或预处理器覆盖特定的GUI绑定

Java 通过侦听器、侦听器或预处理器覆盖特定的GUI绑定,java,dependency-injection,binding,mocking,guice,Java,Dependency Injection,Binding,Mocking,Guice,我想知道Guice中是否有一种方法可以在绑定创建之前通过使用侦听器或拦截器覆盖绑定 我的设想是: 我有一个绑定客户端的模块a,例如: public static class ProdModule extends AbstractModule { @Override protected void configure() { bind(Client.class).toInstance(ClientBuilder.newBuilder().bui

我想知道Guice中是否有一种方法可以在绑定创建之前通过使用侦听器或拦截器覆盖绑定

我的设想是:

我有一个绑定客户端的模块a,例如:

public static class ProdModule extends AbstractModule {
        @Override
        protected void configure() {
            bind(Client.class).toInstance(ClientBuilder.newBuilder().build());
        }
    }
这种绑定需要模拟。因此,我想在测试中添加一个新模块来注册一个侦听器(或其他什么),这样当Guice试图解析该绑定时,我就可以用我想要的任何绑定替换它

我确实知道
模块。覆盖(…)
但是这不能用于我的设置。实例化喷油器的代码本质上隐藏在依赖项中。我没有权限更改代码以使用模块覆盖,但是我可以添加任意数量的新模块

我不想替换整个模块,也不想更改模块代码

我一直在尝试一些不起作用的东西,或者我不知道如何使用它们:

我尝试使用
ProvisionListener
。这“有些”奏效了。我可以通过使用反射和更改条款上的结果字段来覆盖特定的提供者。这对实例绑定不起作用


我试着使用
ElementVisitor
BindingTargetVisitor
,但是它们并没有真正为我做任何事情。我可能不太明白这两位访客的目的是什么,我也没有找到太多的文档或例子

看起来你是在向后解决这个问题——依赖注入是为了支持测试而存在的,因此如果你在使用DI框架的同时难以编写可测试的代码,那么值得退一步,在更高的层次上找出问题所在,而不是试图让框架按你认为应该的方式运行

“这个装订需要嘲笑。”这是一个巨大的危险信号。您几乎不需要绑定mock对象,因为mock很脆弱,通常用于单用途单元测试,而不是由应用程序中的DI框架提供

如果您正在编写单元测试,那么根本不需要框架——只需直接实例化被测试的类,并传递必要的模拟。多亏了依赖项注入,如果类的所有依赖项都被模拟出来,那么您应该能够在隔离状态下快速地对类进行单元测试,而不需要框架

如果您正在编写集成或其他更大的测试,因此需要构建一个注入器并作为一个整体测试系统,理想情况下,您应该拥有无法安全测试的组件的伪(而不是模拟)实现,以及为此类测试安装的备用模块。例如,您的测试注入器将安装
FakeCreditCardProcessorModule
而不是
CreditCardProcessorModule
,并且提供您尝试测试的绑定的模块松散耦合到不关心安装了哪个处理器模块。如果由于过度耦合的模块而无法使用此选项,则可以使用
modules.override()
来伪造单个绑定

只有在测试模块逻辑本身时,才应该绑定mock(尽管通常不鼓励在模块中进行复杂的逻辑测试)。您应该只安装测试中的模块,同时安装一个单独的模块,该模块为任何需要的绑定绑定mock。这是模拟在DI框架中真正有意义的唯一一次


如果上述情况均不适用,请提供有关您尝试测试内容的更多详细信息。

从您如何描述您的限制,无法做到这一点。@TavianBarnes谢谢。恐怕情况就是这样。我目前正试图绕过我的限制来使用模块#覆盖“我不想替换整个模块,也不想更改模块代码”-为什么不?这不是你的密码吗?或者你只是想避免重构你的模块?嗨,谢谢你的回答。我相信这是一个整合测试。我同意你所说的。我的一个问题是我不想创建假模块(例如,如果实际prod模块中的某些内容发生更改,假模块将丢失该内容)。因此,我想让应用程序单独运行,但只替换一个类(本例中为客户机)。我想到了一个假客户端,但这并不像替换java bean那么简单,所以我认为模拟它会让我省去一些麻烦。如果prod模块中的某些内容发生了变化,您对该模块的测试应该会开始失败(例如,由于缺少绑定),所以通常应该可以。理想情况下,每个模块都表示提供特定绑定的明确解耦组件(例如数据库模块),这使得引入提供相同绑定的假模块变得容易。如果这看起来不可行,那么您的模块可能太复杂,您可以从将它们拆分为更小、逻辑上更清晰的组件中获益。这就是我最后所做的。首先,将模块拆分为更小更具体的模块,对于我想要覆盖的特定绑定,引入返回实例并可以覆盖的方法。通过这种方式,我的伪模块可以扩展我的prod模块,然后简单地替换我需要的特定值伪模块和模拟模块当然都有自己的折衷方案,但是如果您的测试足够复杂,需要一个真正的注入器,那么模拟模块就不太可能满足要求(例如,同一个模拟模块可能会被多次注入不同的调用站点)。如果您正在测试的逻辑足够简单,mock就足够了,那么您最好自己构造被测对象并直接传递mock。如果两种情况都不适用,我会重新访问您的测试(因为它们与模块的行为紧密耦合),或者您的模块本身(因为它们有太多的内部行为)。