Как Mocks предназначены для использования? - PullRequest
23 голосов
/ 12 сентября 2008

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

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

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

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

Ответы [ 9 ]

19 голосов
/ 12 сентября 2008

Я рекомендую вам взглянуть на статью Мартина Фаулера Насмешки не являются заглушками для более авторитетного обращения с издевательствами, чем я могу вам дать.

Цель mocks состоит в модульном тестировании вашего кода в изоляции зависимостей, чтобы вы могли по-настоящему протестировать кусок кода на уровне «модуля». Тестируемый код - это реальная сделка, и любой другой фрагмент кода, на который он опирается (через параметры или внедрение зависимостей и т. Д.), Является «Mock» (пустой реализацией, которая всегда возвращает ожидаемые значения при вызове одного из его методов)

Поначалу издевательства могут показаться утомительными, но они делают модульное тестирование намного проще и надежнее, когда вы освоите их использование. Большинство языков имеют библиотеки Mock, которые делают насмешки относительно тривиальными. Если вы используете Java, я порекомендую мой личный фаворит: EasyMock.

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

15 голосов
/ 12 сентября 2008

Не ходи темным путем, Мастер Люк. :) Не надо издеваться над всем. Ты мог, но не должен ... вот почему.

  • Если вы продолжите тестировать каждый метод в отдельности, у вас будут сюрпризы, и вы будете готовы к работе, когда соберете их все вместе BIG BANG . Мы строим объекты, чтобы они могли работать вместе, чтобы решить большую проблему. Сами по себе они незначительны. Вам необходимо знать, все ли соавторы работают должным образом .
  • Издевается делает тесты хрупкими , вводя дублирование - Да, я знаю, это звучит тревожно. Для каждого макета, ожидаемого вами, есть n мест, где существует сигнатура вашего метода. Фактический код и ваши ложные ожидания (в нескольких тестах). Изменить реальный код проще ... обновление всех ложных ожиданий утомительно.
  • Ваш тест теперь доступен для инсайдерской информации о реализации . Таким образом, ваш тест зависит от того, как вы решили реализовать решение ... плохо. Тесты должны быть независимой спецификацией, которая может быть удовлетворена несколькими решениями. У меня должна быть возможность просто нажать «Удалить» на блоке кода и переопределить без необходимости перезаписывать набор тестов , потому что требования остаются прежними.

В заключение я скажу: «Если он крякает как утка, ходит как утка, то, вероятно, это утка» - Если он чувствует себя не так ... это, вероятно, так. * Используйте mocks для абстрагирования проблемных детей, таких как операции ввода-вывода, базы данных, сторонние компоненты и т. Д. Как соль, некоторые из них необходимы .. слишком много и: x *
Это священная война тестирования на основе государства против итераций. Поиск в Google даст вам более глубокое понимание.

Уточнение: я бьюсь о сопротивлении w.r.t. интеграционные тесты тут :) Так что уточняю мой стенд ..

  • Моты не фигурируют в «Приемочных тестах» / области интеграции. Вы найдете их только в мире модульного тестирования ... и это мое внимание здесь.
  • Приемочные испытания различны и очень необходимы - не умаляя их. Но юнит-тесты и приемочные тесты разные и должны быть разными.
  • Все соавторы в компоненте или пакете не должны быть изолированы друг от друга. Как микрооптимизация, которая является Overkill. Они существуют для решения проблемы вместе .. сплоченности.
2 голосов
/ 12 сентября 2008

Да, я согласен. Я считаю, что издевательство иногда болезненно, но часто необходимо, чтобы ваши тесты действительно становились тестами unit , т. Е. Тестируется только самая маленькая единица, с которой вы можете иметь дело. Это позволяет устранить любые другие факторы, которые могут потенциально повлиять на результат теста. В конечном итоге вы получаете гораздо больше небольших тестов, но становится намного проще определить, где проблема с вашим кодом.

1 голос
/ 18 октября 2008

Моты были изобретены частично, чтобы ответили на вопрос : Как бы вы тестировали объекты, если бы у них не было геттеров или сеттеров?

В наши дни рекомендуется практиковаться в том, чтобы издеваться над ролями, а не объектами. Используйте Mocks как инструмент проектирования, чтобы говорить о совместной работе и разделении обязанностей, а не как о «умных тупиках».

1 голос
/ 23 сентября 2008

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

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

1 голос
/ 12 сентября 2008

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

Когда кто-то пытается зарегистрироваться, CheckInUi отправляет объект CheckInInfo объекту CheckInMediator , который проверяет его, используя CheckInValidator затем, если все в порядке, он заполняет объект домена с именем Транзакция с помощью CheckInInfo , используя CheckInInfoAdapter , затем передает Транзакцию в экземпляр ITransactionDao.SaveTransaction () для постоянства.

Я сейчас пишу несколько автоматизированных интеграционных тестов и, очевидно, CheckInUi и ITransactionDao являются окнами для внешних систем, и они должны быть издевались. Но кто сказал, что в какой-то момент CheckInValidator не будет звонить в веб-службу? Вот почему, когда вы пишете модульные тесты , вы предполагаете, что все, кроме специфических функций вашего класса, является внешней системой. Поэтому в моем модульном тесте CheckInMediator я макетирую все объекты, с которыми он разговаривает.

РЕДАКТИРОВАТЬ: Гишу технически правильно, не все должны быть подделаны, например, я не насмехаюсь CheckInInfo , так как это просто контейнер для данных. Однако все, что вы когда-либо видели в качестве внешней службы (а это почти все, что преобразует данные или имеет побочные эффекты), должно быть осмеяно.

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

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

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

Кстати, один из наших ИТ-специалистов только что пришел и дал мне бесплатный ноутбук!

1 голос
/ 12 сентября 2008

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

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

Если бы каждый разработчик в вашем проекте потратил время на написание модульных тестов, то эти 16 уровней (косвенного) не были бы такой большой проблемой. Надеюсь, у вас должен быть тестовый охват с самого начала, верно? :)

Кроме того, не забудьте написать функциональный / интеграционный тест между объектами в сотрудничестве. Или вы можете что-то упустить. Эти тесты не нужно запускать часто, но они по-прежнему важны.

1 голос
/ 12 сентября 2008

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

Что касается сложности, я считаю, что тесты должны быть простыми для написания, просто потому, что вы пишете больше тестов, если они есть.

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

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

0 голосов
/ 18 июля 2010

Поддельные объекты 1) часто используются в качестве средства для изоляции тестируемого кода, НО 2), как уже указывал keithb, важно " сосредоточиться на отношениях между взаимодействующими объектами ". Эта статья дает некоторые идеи и историю, связанную с предметом: Ответственный дизайн с фиктивными объектами .

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