Я начал использовать moq для издевательства. Может кто-нибудь объяснить мне концепцию строгих и нестрогих моков? Как их можно использовать в moq?
edit: в каком сценарии мы используем макет?
Я начал использовать moq для издевательства. Может кто-нибудь объяснить мне концепцию строгих и нестрогих моков? Как их можно использовать в moq?
edit: в каком сценарии мы используем макет?
Я не уверен насчет moq конкретно, но вот как строгие mocks работают в Rhino. Я заявляю, что ожидаю вызова foo.Bar
моего объекта foo
:
foo.Expect(f => f.Bar()).Returns(5);
Если вызывающий код
foo.Bar();
тогда я в порядке, потому что ожидания полностью оправдались.
Однако, если код вызова:
foo.Quux(12);
foo.Bar();
тогда мои ожидания не оправдались, потому что я явно не ожидал вызова foo.Quux
.
Подводя итог, строгий макет не удастся сразу же, если что-то отличается от ожиданий. С другой стороны, нестрогий макет (или заглушка) с радостью «проигнорирует» вызов foo.Quux
и должен вернуть default(T)
для типа возврата T
из foo.Quux
.
Создатель Rhino строгое (и предпочитаете заглушки), потому что обычно вы не хотите, чтобы тест завершался неудачно при получении неожиданного вызова, как указано выше. Это значительно усложняет рефакторинг вашего кода, когда вам нужно исправить десятки тестов, основанных на точном исходном поведении.
Mock
, который принимает MockBehavior
аргумент. Поведение по умолчанию (без указания MockBehavior
) кажется нестрогим (они называют это свободным).
- person Mark Rushakoff; 28.06.2010
Когда-нибудь сталкивались с данным / Когда / Тогда?
Этот шаблон появляется в сценариях BDD, а также актуален для модульных тестов.
Если вы настраиваете контекст, вы собираетесь использовать информацию, которую предоставляет этот контекст. Например, если вы ищете что-то по Id, это контекст. Если его нет, тест не запустится. В этом случае вы хотите использовать NiceMock или заглушку или что-то еще - способ работы Moq по умолчанию.
Если вы хотите проверить результат, вы можете использовать Moq verify. В этом случае вы хотите записывать соответствующие взаимодействия. К счастью, это также способ запуска Moq по умолчанию. Он не будет жаловаться, если случится что-то, что вас не интересовало во время этого теста.
StrictMock существует, когда вы не хотите, чтобы произошло неожиданное взаимодействие. Это то, как раньше работали фреймворки для фиксации в старом стиле. Если вы делаете примеры в стиле BDD, вам это, вероятно, не понадобится. Он имеет тенденцию делать тесты немного хрупкими и трудными для чтения, чем если бы вы разделяли аспекты поведения, которые вас интересуют. Вы должны установить ожидания как для контекста, так и для результата, для всех результатов, которые будут иметь место, независимо от интересны они или нет.
Например, если вы тестируете контроллер и имитируете как свой валидатор, так и свой репозиторий, и хотите проверить, что вы сохранили свой объект, с помощью строгого макета вы также должны убедиться, что вы сначала проверили объект. . Я предпочитаю рассматривать эти два аспекта поведения в отдельных примерах, потому что это облегчает мне понимание ценности и поведения контроллера.
За последние четыре года я не нашел ни одного примера, который требовал бы использования строгого макета - либо это был результат, который я хотел бы проверить (даже если я проверю, сколько раз он вызывается), либо контекст, для которого я могу скажите, правильно ли я отвечаю на предоставленную информацию. Итак, отвечая на ваш вопрос:
NB: Я сильно предвзято отношусь к BDD, поэтому заядлые TDD-специалисты могут не согласиться со мной, и это будет правильным с точки зрения их работы.
Вот хорошая статья.
Обычно у меня получается что-то вроде этого
public class TestThis {
private final Collaborator1 collaborator1;
private final Collaborator2 collaborator2;
private final Collaborator2 collaborator3;
TestThis(Collaborator1 collaborator1, Collaborator2 collaborator2, Collaborator3 collaborator3) {
this.collaborator1 = collaborator1;
this.collaborator2 = collaborator2;
this.collaborator3 = collaborator3;
}
public Login login(String username) {
User user = collaborator1.getUser(username);
collaborator2.notify(user);
return collaborator3.login(user);
}
}
... и я использую Strict mocks для трех соавторов, чтобы проверить логин (имя пользователя). Я не понимаю, почему нельзя использовать Strict Mocks.
У меня есть простое соглашение:
Используйте строгие макеты, когда тестируемая система (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.
}