У меня есть топология шторма, в которой используется guice для введения различных зависимостей в болты. Зависимости не вводятся конструктором из-за проблем сериализации / десериализации шторма. Мы передаем объект guice injector
конструктору болта и используем его в методе prepare
болта для ввода в поле зависимостей (неидеально, я знаю, но пока не знаю лучшего сценария).
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
}
}
Я пишу модульные тесты для болта с тестовым модулем guice, так что я могу вводить фиктивные зависимости для таких вещей, как контроллеры баз данных и т. д. Для этого мне нужно привязать класс контроллера к фиктивному классу:
bind(MyController::class.java).toInstance(MockController())
Однако, чтобы это работало, мне нужно заставить MockController
наследовать тот же интерфейс / суперкласс, что и MyController
. В чем я не уверен, так это в том, что добавление интерфейса к MyController
только для модульного тестирования является хорошей практикой.
В Kotlin есть функция, позволяющая реализовать функцию как интерфейс. См. 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.
Я понимаю желание сгруппировать связанные методы в один класс, но с Kotlin вы можете получить лучшее из обоих. У вас могут быть очень простые классы с одним общедоступным методом, но сгруппировать эти связанные классы в один файл. Трудно объяснить, почему это может помочь, но это действительно может упростить тестирование и сделать его более читаемым.
Вы также можете использовать mockk https://mockk.io/, чтобы напрямую имитировать зависимости.
Также у MyController
есть несколько методов, которые мне нужно смоделировать. Значит, если я смогу сделать это только один раз, это может не удовлетворить мои потребности?
Я кратко прочитал документацию по mockK
, и она выглядит очень интересно. Тем не менее, все примеры, которые я видел в документе, насмехались над объектом напрямую, а не над косвенным объектом, производным от инжектора guice.
Я не знаю, как будет выглядеть функция как интерфейс. Можете показать мне, как это выглядит на моем примере?