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

Moq, строгое и свободное использование

В прошлом я использовал только Rhino Mocks, с типичным строгим макетом. Я сейчас работаю с Moq по проекту, и мне интересно, как правильно использовать его.

Предположим, что у меня есть объект Foo с помощью метода Bar, который вызывает метод Bizz на объекте Buzz.

В моем тесте я хочу проверить, что Bizz вызывается, поэтому я чувствую, что возможны два варианта:

Со строгим макетом

var mockBuzz= new Mock<IBuzz>(MockBehavior.Strict);
mockBuzz.Setup(x => x.Bizz()); //test will fail if Bizz method not called
foo.Buzz = mockBuzz
foo.Bar();
mockBuzz.VerifyAll();

С рывком

var mockBuzz= new Mock<IBuzz>();    
foo.Buzz = mockBuzz
foo.Bar();
mockBuzz.Verify(x => x.Bizz()) //test will fail if Bizz method not called

Есть ли стандартный или нормальный способ сделать это?

4b9b3361

Ответ 1

Раньше я использовал строгие макеты, когда я начинал использовать mocks в модульных тестах. Это продолжалось недолго. Есть действительно 2 причины, почему я прекратил это делать:

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

Из-за этого я настоятельно рекомендую использовать свободные макеты в своих модульных тестах.

Ответ 2

У меня есть простая конвенция:

  • Использовать строгие макеты, когда тестируемая система (SUT) делегирует вызов базовому слоганному слою, не изменяя или применяя какую-либо бизнес-логику к аргументам, переданным самому себе.

  • Использовать свободные макеты, когда SUT применяет бизнес-логику к аргументам, переданным самим себе, и передает некоторые производные/измененные значения на посмеянный уровень.

Например: Допустим, у нас есть провайдер базы данных StudentDAL, который имеет два метода:

Интерфейс доступа к данным выглядит примерно так:

public Student GetStudentById(int id);
public IList<Student> GetStudents(int ageFilter, int classId);

Реализация, которая потребляет этот DAL, выглядит следующим образом:

public Student FindStudent(int id)
{
   //StudentDAL dependency injected
   return StudentDAL.GetStudentById(id);
   //Use strict mock to test this
}
public IList<Student> GetStudentsForClass(StudentListRequest studentListRequest)
{
  //StudentDAL dependency injected
  //age filter is derived from the request and then passed on to the underlying layer
  int ageFilter = DateTime.Now.Year - studentListRequest.DateOfBirthFilter.Year;
  return StudentDAL.GetStudents(ageFilter , studentListRequest.ClassId)
  //Use loose mock and use verify api of MOQ to make sure that the age filter is correctly passed on.

}

Ответ 3

У меня есть опыт разработки С++/не .NET, и я недавно был в .NET, поэтому у меня были определенные ожидания, когда я впервые использовал Moq. Я пытался понять, что WTF работает с моим тестом, и почему код, который я тестировал, выбрасывал случайное исключение вместо библиотеки Mock, рассказывающей мне, какую функцию пытался вызвать код. Поэтому я обнаружил, что мне нужно включить поведение Strict, которое было озадачено, - и затем я столкнулся с этим вопросом, который, как я видел, еще не получил ответа.

Режим Свободный, и тот факт, что он по умолчанию , безумный. Что, на самом деле, является точкой библиотеки Mock, которая делает что-то совершенно непредсказуемое, которое вы явно не указали в нем, должно делать?

Я полностью не согласен с пунктами, перечисленными в других ответах в поддержку Loose mode. Нет никаких оснований для его использования, и я никогда не захочу. Когда я пишу unit test, я хочу быть уверенным, что происходит - если я знаю, что функция должна вернуть нуль, я верну ее. Я хочу, чтобы мои тесты были хрупкими (в том, что важно), чтобы я мог их исправить и добавить в набор тестового кода строки настройки, которые являются явной информацией, которая описывает мне, что именно будет делать мое программное обеспечение.

Вопрос: есть ли стандартный и нормальный способ сделать это?

Да - с точки зрения программирования вообще, то есть других языков и вне мира .NET, вы должны использовать Strict всегда. Доброта знает, почему это не по умолчанию в Moq.

Ответ 4

Я лично, будучи новичком в насмешливости и Moq, чувствует, что начало с Strict-режима помогает лучше понять внутренности и что происходит. "Loose" иногда скрывает детали и передает тест, который новичок-новичок может не увидеть. Как только у вас будут свои умственные способности вниз - Loose, вероятно, будет намного более продуктивным - например, в этом случае сохранение строки с помощью "Setup" и просто использование "Verify".