我有一个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
添加一个接口是否是一个好的做法。
静态编程语言有一个特性,允许您将函数实现为接口。请参阅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/直接模拟依赖关系。