提问者:小点点

静态编程语言:为guice注入的依赖项添加一个接口,以便我们可以仅出于单元测试目的模拟它们?


我有一个Storm拓扑,它使用guice在bolt中注入各种依赖项。由于Storm序列化/反序列化问题,依赖项没有构造器注入。我们将一个guiceinjector对象传递给bolt构造函数,并在bolt的准备方法中使用它来字段注入依赖项(不理想,我知道,但目前不知道更好的场景)。

class MyBolt(val injector: Injector) : AbstractRichBolt() {
   @Inject
   @Transient
   private lateinit var myController: MyController
   ...
   override fun prepare(...) {
       this.injector.injectMembers(this)
   }
   override fun execute(input: Tuple) {
       // use myController in our logic here
   }
}

我正在使用test guice模块为bolt编写单元测试,以便我可以为数据库控制器等注入模拟依赖项。为此,我需要将控制器类绑定到模拟类:

bind(MyController::class.java).toInstance(MockController())

然而,要做到这一点,我必须让MockController继承自与MyController相同的接口/超类。我不确定的是,仅仅为了单元测试,向MyController添加一个接口是否是一个好的做法。


共1个答案

匿名用户

静态编程语言有一个特性,允许您将函数实现为接口。请参阅https://kotlinlang.org/docs/reference/lambdas.html#instantiating-a-function-type.

class MyController : (Int) -> String {
    override fun invoke(in: Int) : String = "Real Logic"
}

然后用你在测试中想要的行为做一个双重测试

class StubMyController : (Int) -> String {
    override fun invoke(in: Int) : String = "Test Logic"
}

然后用注射器注射双重测试

bind(MyController::class.java).toInstance(StubMyController())

对于一个类,你只能这样做一次。我已经使用了这个特性,而不是额外的接口或向类添加开放。它认为它非常鼓励SOLID原则。还有更多,但是在一个类上只有一个公共方法肯定有助于保持一个专注于SOLID。

我理解将相关方法分组到单个类中的愿望,但使用静态编程语言,您可以两者兼得。您可以使用一个公共方法拥有非常简单的类,但将这些相关的类分组到单个文件中。很难解释为什么这会有所帮助,但它确实可以使测试更容易,更具可读性。

也可以使用mockkhttps://mockk.io/直接模拟依赖关系。