Как протестировать метод, имитируя вложенные методы?

#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 , который может быть макетом или реальным