Подтвердить что ты не робот

Когда ожидать и когда засевать?

Я использую NMock2, и я разработал следующие классы NMock для представления некоторых общих концепций фреймворка:

  • Expect: это указывает на то, что должен был вернуть издеваемый метод, и говорит, что вызов должен произойти или тест завершился неудачно (когда он сопровождается вызовом VerifyAllExpectationsHaveBeenMet()).

  • Stub: это указывает на то, что должен был вернуть издеваемый метод, но не может вызвать потерю теста.

Итак, что мне делать, когда?

4b9b3361

Ответ 1

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

  • Mock: только когда вы явно пытаетесь проверить поведение тестируемого объекта (т.е. ваш тест говорит, что этот объект должен вызывать этот объект).
  • Stub. Когда вы пытаетесь протестировать некоторые функции/поведение, но для того, чтобы получить эту работу, вам нужно полагаться на некоторые внешние объекты (т.е. ваш тест говорит, что этот объект должен что-то делать, но как побочный эффект, он может назвать этот объект)

Это становится яснее, когда вы убедитесь, что каждый из ваших модулей тестирует только одно. Конечно, если вы попытаетесь протестировать все в одном тесте, тогда вы также можете ожидать все. Но только ожидая того, что проверяет конкретный unit test, ваш код намного яснее, потому что вы можете сразу увидеть, что цель теста.

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

Изменить. Это может быть яснее на основе надуманного примера, когда объект калькулятора проверяет все дополнения к базе данных (в псевдокоде)...

public void CalculateShouldAddTwoNumbersCorrectly() {
    var auditDB = //Get mock object of Audit DB
    //Stub out the audit functionality...
    var calculator = new Calculator(auditDB);
    int result = calculator.Add(1, 2);
    //assert that result is 3
}

public void CalculateShouldAuditAddsToTheDatabase() {
    var auditDB = //Get mock object of Audit DB
    //Expect the audit functionality...
    var calculator = new Calculator(auditDB);
    int result = calculator.Add(1, 2);
    //verify that the audit was performed.
}

Итак, в первом тестовом примере мы тестируем функциональность метода Add и не заботимся о том, произошло ли событие аудита или нет, но мы знаем, что калькулятор не будет работать с аудитDB так что мы просто остановим его, чтобы дать нам минимум функциональности, чтобы наш конкретный тестовый пример работал. Во втором тесте мы специально проверяем, что, когда вы выполняете Add, происходит событие аудита, поэтому мы используем ожидания (обратите внимание, что нам даже неважно, каков результат, поскольку это не то, что мы тестируем).

Да, вы могли бы объединить два случая в один, сделать ожидания и утверждать, что ваш результат равен 3, но затем вы тестируете два случая в одном unit test. Это сделало бы ваши тесты более хрупкими (поскольку там была большая площадь поверхности вещей, которые могли бы измениться, чтобы сломать тест) и менее ясны (поскольку, когда объединенный тест терпит неудачу, не сразу становится очевидным, в чем проблема... добавление не работает, или аудит не работает?)

Ответ 2

"Ожидайте действия, заглушки". Если вызов должен изменить состояние мира за пределами тестируемого объекта, тогда сделайте это ожидание - вы заботитесь о том, как он вызван. Если это просто запрос, вы можете называть его один или шесть раз без изменения состояния системы, а затем отключите вызов.

Еще одна вещь, обратите внимание, что различие между окурками и ожиданиями - это отдельные вызовы, а не целые объекты.

Ответ 3

Ну... ИМХО, это не может быть проще: если ваш тест посвящен обеспечению того, что ваш докладчик вызовет "Сохранить", сделайте "Ожидание". если ваш тест касается обеспечения того, чтобы ваш Presenter обработал исключение грациозно, если Save throws up, сделайте Stub.

Подробнее см. этот подкаст от Hanselman и Osherove (автор The Art Of Unit Testing)