Должен ли я издеваться над чертой или издеваться над классом, используя Scala Mock

Скажем, у меня есть следующее:

@ImplementedBy(classOf[DefaultFoo])
trait Foo {
  def a (s : String) : Int
}

class DefaultFoo @Inject()() extends Foo{

  override def a (s : String) = 1

}

@ImplementedBy(classOf[DefaultBaz])
trait Baz {
  def b (s : String) : Int
}

class DefaultBaz @Inject()(val f :Foo) extends Baz{

  override def a (s : String) = 1

}

Если я хочу протестировать, скажем, DefaultBaz, я обычно использую ScalaMock, и в своей тестовой спецификации я бы издевался следующим образом:

class DefaultBazSpec extends AnyWordSpec with MockFactory{

   val mockFoo = mock[Foo]
val b = new DefaultBaz(mockFoo)

   // write tests
}

Но я также мог бы сделать это:

val mockFoo = mock[DefaultFoo]

Какой лучше? Издеваться над чертой или реализацией класса по умолчанию?


person Mojo    schedule 25.01.2021    source источник
comment
Почему бы просто не расширить трейт с помощью простого класса, который делает то же, что и макет, но без отражения и причудливого синтаксиса.   -  person Luis Miguel Mejía Suárez    schedule 25.01.2021
comment
Я не привел хороший пример. Я хотел описать сценарий, в котором Foo внедряется в другой класс. И тесты для этого класса будут использовать фиктивную версию Foo с использованием Scalamock. Теперь я мог бы сделать mock[Foo] или mock[DefaultFoo] . хотел узнать плюсы и минусы   -  person Mojo    schedule 25.01.2021
comment
Я думаю, у вас есть некоторые ошибки в вашем фрагменте, вы, вероятно, хотите, чтобы DefaultBaz расширял Baz и получал экземпляр Foo в качестве аргумента. - в любом случае, я знаю, что вы привыкли к java-способу работы с отражением для решения (усложнения) каждой тривиальной проблемы, такой как передача зависимостей и тестирование. Но многие люди в Scala предпочитают все упрощать и просто передавать зависимости вручную и использовать простые заглушки для тестирования вместо макетов.   -  person Luis Miguel Mejía Suárez    schedule 25.01.2021
comment
Да, извините, я исправил это, а также показываю, что использую структуру Guice DI. Я знаю, что подход FP говорит не использовать DI, но я использую Play Framework, и он поставляется с Guice DI, поэтому я использую его, поэтому я тестирую таким образом,   -  person Mojo    schedule 25.01.2021
comment
Опять же, в этом случае вам действительно не нужно издеваться, вы можете просто создать фиктивный класс, который расширяет Foo, и предоставить там ложную реализацию, которую вы бы сделали с фиктивным, и передать экземпляр этого класса в DefaultBaz для проверки ti. Но если вы предпочитаете продолжать использовать насмешки по какой-либо причине (согласованность с остальной кодовой базой является веской причиной), я думаю, вам следует имитировать Foo   -  person Luis Miguel Mejía Suárez    schedule 25.01.2021
comment
Спасибо @LuisMiguelMejíaSuárez - да, я сейчас так и делаю. Но если бы я издевался над DefaultFoo, было бы это плохо?   -  person Mojo    schedule 25.01.2021
comment
Главным образом потому, что ваш DefaultBaz должен работать для любого Foo, а также потому, что имитировать DefaultFoo может быть сложнее, чем простой интерфейс (который, кстати, не нуждается в имитировании, но вы, должно быть, устали от того, что я повторяю это снова и снова).   -  person Luis Miguel Mejía Suárez    schedule 25.01.2021
comment
Да, я так и думал. Что, если DefaultFoo требует внедрения 5 зависимостей. Я, конечно, не хочу тратить время на то, чтобы высмеивать какое-то поведение метода a. Так что вместо этого я издеваюсь над Foo, и мне не нужно во всё это вмешиваться.   -  person Mojo    schedule 25.01.2021
comment
Отвечает ли это на ваш вопрос? Насмешка над классом и насмешка над его интерфейсом   -  person M.K.    schedule 26.01.2021


Ответы (1)


Лучше не использовать ни то, ни другое. Насмешек вообще следует избегать (особенно в Scala).

Но даже если вы решили использовать моки, имитация тестируемого класса уничтожает всю цель тестирования: тестируемый код не имеет ничего общего с рабочим кодом.

Макеты предназначены для имитации зависимостей (например, параметров конструктора или аргументов метода) тестируемого класса.

person simpadjo    schedule 25.01.2021
comment
Я использую моки, чтобы имитировать поведение методов в классе в приведенном выше примере. Скажем, например, у меня был другой класс, который вводил Foo. Затем в моем тесте для этого другого класса я бы просто сделал val f = mock[Foo], а затем написал макеты для поведения метода a, чтобы их можно было использовать для тестирования этого другого класса. Смотрите мой обновленный пост. Он лучше описывает сценарий - person Mojo; 25.01.2021
comment
Тогда издевательство над Foo — меньшее зло. - person simpadjo; 25.01.2021
comment
Что плохого в том, чтобы издеваться над DefaultFoo - вот мой главный вопрос @simajdo - person Mojo; 25.01.2021