#scala #methods #mockito #traits
#scala #методы #mockito #Трейты
Вопрос:
Я пытаюсь протестировать, Object.method
который содержит некоторые вложенные методы из Trait
, кроме некоторых вычислений. Эти вложенные методы должны быть высмеяны (они обращаются к БД, поэтому я хочу высмеять их ответы).
Когда я вызываю real Object.method
, он должен пропустить вызов вложенных методов и получить то, что я хочу. Я пробовал издеваться над ними, но тест все еще вызывает их.
Вот мой пример исходного кода:
trait MyTrait {
def myMethodToMock(a: String): String
}
object MyObject extends MyTrait {
def myParentMethod(a:String) = {
val b = myMethodToMock(a)
val c = a b
c
}
}
Затем в моем тесте:
val myTraitMock = mock[MyTrait]
when(myTraitMock.myMethodToMock(a)).thenReturn(b)
//Then I call the parent method:
assert(MyObject.myParentMethod(a) equals c)
Он выдает исключение NullPointerException, поскольку он все еще обращается к myMethodToMock
Ответ №1:
Ваш код не компилируется, поэтому я собираюсь предположить некоторые вещи из того, что вы на самом деле пытаетесь здесь сделать …
Вы заглушаете метод в макет, а затем вызываете его в совершенно не связанном экземпляре. Неудивительно, что это не работает.
Хорошее эмпирическое правило (и лучшая практика) — никогда не имитировать классы, которые вы на самом деле тестируете. Разделите все, что вы хотите имитировать и тестировать отдельно, в отдельный класс. Это также известно как принцип единой ответственности (каждый компонент должен отвечать за одну вещь).
trait MyTrait {
def myMethodToMock(a: String): String
}
object MyTrait extends MyTrait {
def myMethodtoMock(a: String) = ???
}
class MyObject(helper: MyTrait = MyTrait) {
def myParentMethod(a: String) = a helper.myMethodToMock(a)
}
object MyObject extends MyObject()
Теперь вы можете написать свой тест следующим образом:
val myTraitMock = mock[MyTrait]
when(myTraitMock.myMethodToMock(any)).thenReturn("b")
new MyObject(myTraitMock).myParentMethod("a") shouldBe "ab"
verify(myTraitMock).myMethodToMock("a")
Основное отличие здесь в том, что вы передаете свой макет в конструктор объекта, так что, когда он вызывает метод, это будет тот, который вы заглушили, а не реализация, предоставляемая классом по умолчанию.
Комментарии:
1. Спасибо @Dima. Мы, наконец, использовали класс case MyObject.
Ответ №2:
Вы должны использовать композицию, а не наследование, чтобы вы могли внедрить экземпляр MyTrait
, который может быть макетом или реальным