Зачем нужны макетные фреймворки?

Я работал с кодом, для которого был написан тест NUnit. Но я никогда не работал с макетными фреймворками. Кто они такие? Я понимаю внедрение зависимостей и то, как это помогает улучшить тестируемость. Я имею в виду, что все зависимости можно смоделировать во время модульного тестирования. Но тогда зачем нам макетные фреймворки? Разве мы не можем просто создать фиктивные объекты и предоставить зависимости. Я что-то упустил? Спасибо.


person Sandbox    schedule 11.11.2009    source источник


Ответы (11)


  • Это упрощает издевательство
  • Обычно они позволяют выражать проверяемые утверждения, относящиеся к взаимодействию между объектами.

Вот вам пример:

var extension = MockRepository
    .GenerateMock<IContextExtension<StandardContext>>();
  var ctx = new StandardContext();
  ctx.AddExtension(extension);
  extension.AssertWasCalled(
    e=>e.Attach(null), 
    o=>o.Constraints(Is.Equal(ctx)));

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

person flq    schedule 11.11.2009

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

Как всегда, если использование фреймворка слишком усложняет его использование, не используйте его.

person Justin Niessner    schedule 11.11.2009

Иногда при работе со сторонними библиотеками или даже при работе с некоторыми аспектами платформы .NET чрезвычайно сложно написать тесты для некоторых ситуаций - например, для HttpContext или объекта Sharepoint. Создание имитирующих объектов для них может стать очень обременительным, поэтому фреймворки фиксации позаботятся об основах, чтобы мы могли сосредоточиться на том, что делает наши приложения уникальными.

person Rex M    schedule 11.11.2009

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

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

Ознакомьтесь с Rhino Mocks, чтобы увидеть, насколько мощной может быть среда имитации.

person reustmd    schedule 11.11.2009

Мок-объекты заменяют любые большие / сложные / внешние объекты, к которым вашему коду необходим доступ для запуска.

Они полезны по нескольким причинам:

  • Ваши тесты должны выполняться быстро и легко. Если ваш код зависит, скажем, от подключения к базе данных, вам потребуется полностью настроенная и заполненная база данных для запуска ваших тестов. Это может раздражать, поэтому вы создаете замену - «имитацию» - объекта подключения к базе данных, который просто имитирует базу данных.

  • Вы можете точно контролировать, какой вывод будет выводиться из объектов Mock, и, следовательно, можете использовать их в качестве контролируемых источников данных для ваших тестов.

  • Вы можете создать макет до создания реального объекта, чтобы улучшить его интерфейс. Это полезно при разработке через тестирование.

person Frank Krueger    schedule 11.11.2009

Единственная причина использовать имитирующую библиотеку состоит в том, что она упрощает имитацию.

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

Подумайте об этом с точки зрения алгоритмов сортировки, конечно, любой может написать такой, но почему? Если код уже существует и его легко вызвать ... почему бы не использовать его?

person chills42    schedule 11.11.2009
comment
Некоторые фиктивные фреймворки выходят за рамки того, что все это делается вручную, например, фиктивные статики. - person Chris Missal; 14.11.2009

Вы, конечно, можете смоделировать свои зависимости вручную, но с фреймворком это избавляет от утомительной работы. Также стоит изучить обычно доступные утверждения.

person mxmissile    schedule 11.11.2009

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

Например, если у меня есть класс A, содержащий бизнес-правила и логику, которые я хочу протестировать, но этот класс A зависит от классов доступа к данным, других бизнес-классов, даже классов u / i и т. Д., Эти другие классы можно высмеивать. для выполнения определенным образом (или вообще никаким образом в случае свободного имитационного поведения) для проверки логики в вашем классе A на основе всех мыслимых способов, которыми эти другие классы могли бы предположительно вести себя в производственной среде.

Чтобы дать более глубокий пример, предположим, что ваш класс A вызывает метод класса доступа к данным, например

public bool IsOrderOnHold(int orderNumber) {}

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

person Community    schedule 21.04.2010
comment
хорошо сказано. Издевательство позволяет подавить поведение. - person j2emanue; 22.04.2015

Я бы сказал, что нет. Написание тестовых дублей не является большой задачей в 9 случаях из 10. В большинстве случаев это делается почти полностью автоматически, просто попросив resharper реализовать интерфейс для вас, а затем вы просто добавляете незначительные детали, необходимые для этого двойника (потому что вы не используют кучу логики и не создают этих замысловатых супертестовых двойников, верно?

«Но зачем мне раздувать мой тестовый проект кучей тестовых двойников?» - спросите вы. Ну, не надо. принцип СУХОЙ применим и для тестов. Создавайте ХОРОШИЕ тестовые двойники, которые можно использовать повторно и с описательными именами. Это также делает ваши тесты более читабельными.

Одна вещь, которую он ДЕЙСТВИТЕЛЬНО усложняет, - это чрезмерное использование тестовых двойников. Я склонен согласиться с Роем Ошеровым и дядей Бобом, вы действительно не хотите так часто создавать фиктивный объект с какой-то особой конфигурацией. Это сам по себе дизайнерский запах. Используя фреймворк, так легко просто использовать тестовые двойники со сложной логикой практически в каждом тесте, и в конце вы обнаружите, что на самом деле не тестировали свой производственный код, вы просто протестировали чудовищный беспорядок моков, содержащих mocks, содержащие больше mocks. Вы никогда не сделаете этого «случайно», если напишете свои собственные двойники.

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

Я бы порекомендовал любому (ОСОБЕННО новичку) держаться подальше от фреймворков и научиться обходиться без них, а затем, когда они почувствуют, что им действительно нужно, они могут использовать любой фреймворк, который они считают наиболее подходящим, но к тому времени это будет осознанное решение, и они с гораздо меньшей вероятностью будут злоупотреблять фреймворком для создания плохого кода.

person sara    schedule 06.10.2015

Хорошо имитирующие фреймворки делают мою жизнь намного проще и менее утомительной, поэтому я могу тратить время на собственное написание кода. Возьмем, к примеру, Mockito (в мире Java)

 //mock creation
 List mockedList = mock(List.class);

 //using mock object
 mockedList.add("one");
 mockedList.clear();

 //verification
 verify(mockedList).add("one");
 verify(mockedList).clear();

 //stubbing using built-in anyInt() argument matcher
 when(mockedList.get(anyInt())).thenReturn("element");

 //stubbing using hamcrest (let's say isValid() returns your own hamcrest matcher):
 when(mockedList.contains(argThat(isValid()))).thenReturn("element");

 //following prints "element"
 System.out.println(mockedList.get(999));

Хотя это надуманный пример, если вы замените List.class на MyComplex.class, тогда ценность использования фреймворка для фиксации станет очевидной. Вы можете написать свое собственное или обойтись без него, но зачем вам идти по этому пути.

person non sequitor    schedule 11.11.2009

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

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

person Hamish Smith    schedule 11.11.2009