Moq, строгое против свободного использования - PullRequest
48 голосов
/ 14 февраля 2011

В прошлом я использовал только глухие носороги с типичной строгой насмешкой. Сейчас я работаю с 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

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

Ответы [ 4 ]

76 голосов
/ 14 февраля 2011

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

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

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

14 голосов
/ 21 сентября 2016

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

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

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

Вопрос в том - существует ли стандартный и нормальный способ сделать это?

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

9 голосов
/ 22 октября 2013

У меня есть простое соглашение:

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

  2. Используйте свободные макеты, когда 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.

}
4 голосов
/ 21 июня 2013

Лично я, будучи новичком в издевательствах, и Мок чувствуют, что запуск в строгом режиме помогает лучше понять внутренности и то, что происходит.«Свободные» иногда скрывают детали и проходят тест, который новичок moq может не увидеть.Как только у вас упадут навыки насмешки - Loose, вероятно, станет намного более продуктивным - как в этом случае сохранить строку с помощью «Setup» и просто использовать вместо нее «Verify».

...