Классы, которые используют другие классы (как члены или как аргументы методов), нуждаются в экземплярах, которые корректно ведут себя для unit test. Если у вас есть эти классы, и они не вносят никаких дополнительных зависимостей, не лучше ли использовать реальную вещь вместо макета?
Мокки или настоящие классы?
Ответ 1
Я говорю, чтобы использовать реальные классы всякий раз, когда вы можете.
Я очень верим в максимально возможное расширение границ "единичных" тестов. На данный момент они не являются модульными испытаниями в традиционном смысле, а скорее просто автоматическим набором регрессии для вашего приложения. Я все еще практикую TDD и сначала пишу все мои тесты, но мои тесты немного больше, чем у большинства людей, а мои зеленые-красно-зеленые циклы занимают немного больше времени. Но теперь, когда я делаю это некоторое время, я полностью убежден, что модульные тесты в традиционном смысле - это не все, что они треснут.
По моему опыту писать кучу крошечных модульных тестов становится препятствием для рефакторинга в будущем. Если у меня есть класс A, который использует B и я unit test, издеваясь над B, когда я решаю переместить некоторые функции с A на B или наоборот, все мои тесты и изменения должны измениться. Теперь, если у меня есть тесты, которые проверяют, что сквозной поток через систему работает так, как ожидалось, мои тесты действительно помогают мне идентифицировать места, где мои рефакторинги могли вызвать изменение внешнего поведения системы.
Суть в том, что mocks кодифицирует контракт определенного класса и часто в конечном итоге также указывает некоторые детали реализации. Если вы широко используете макеты в своем тестовом наборе, ваша база кода заканчивается большой дополнительной инерцией, которая будет сопротивляться любым будущим усилиям рефакторинга.
Ответ 2
Хорошо использовать "реальную вещь", если у вас есть абсолютный контроль над объектом. Например, если у вас есть объект, у которого есть только свойства и аксессоры, вы, вероятно, в порядке. Если в объекте, который вы хотите использовать, есть логика, вы можете столкнуться с проблемами.
Если unit test для класса a использует экземпляр класса b и изменение, введенное в b breaks b, то тесты для класса a также прерываются. Здесь вы можете столкнуться с проблемами, где, как с макетным объектом, вы всегда можете вернуть правильное значение. Использование "реальной вещи" Может иметь вид свернутых тестов и скрыть настоящую проблему.
У Mocks могут быть и минусы, я думаю, что есть баланс с некоторыми издевательствами и некоторыми реальными объектами, которые вам придется найти для себя.
Ответ 3
Я всегда использую макетную версию зависимости, если зависимость обращается к внешней системе, такой как база данных или веб-служба.
Если это не так, это зависит от сложности двух объектов. Тестирование тестируемого объекта с реальной зависимостью существенно умножает два набора сложностей. Извержение зависимостей позволяет изолировать тестируемый объект. Если любой объект достаточно прост, то сложная сложность все еще работоспособна, и мне не нужна макетная версия.
Как говорили другие, определение интерфейса по зависимостям и впрыскивание его в тестируемый объект значительно облегчает издевательство.
Лично я не знаю, стоит ли использовать строгие mocks и проверять каждый вызов зависимости. Обычно я это делаю, но в основном это привычка.
Вы также можете найти эти полезные вопросы:
Ответ 4
Существует одна хорошая причина, почему вы хотите использовать заглушки /mocks вместо реальных классов. То есть чтобы сделать ваш unit test (чистый unit test) класс под тестированием изолированным от всего остального. Это свойство чрезвычайно полезно, и преимущества для хранения изолированных тестов многочисленны:
- Тесты выполняются быстрее, потому что им не нужно вызывать реализацию реального класса. Если реализация выполняется против файловой системы или реляционной базы данных, тогда тесты станут вялыми. Медленные тесты заставляют разработчиков не запускать модульные тесты так часто. Если вы проводите тестирование Driven Development, то тесты времени на свидание вместе разрушают трату времени разработчиков.
- Будет легче выявлять проблемы, если тест изолирован от тестируемого класса. В отличие от системного теста будет намного сложнее отследить отвратительные ошибки, которые, по-видимому, не видны в трассировке стека, а что нет.
- Тесты менее хрупкие в отношении изменений, выполняемых на внешних классах/интерфейсах, потому что вы просто проверяете тестируемый класс. Низкая хрупкость также является показателем низкой связи, что является хорошей разработкой программного обеспечения.
- Вы тестируете внешнее поведение класса, а не внутреннюю реализацию, которая более полезна при выборе дизайна кода.
Теперь, если вы хотите использовать настоящий класс в своем тесте, это прекрасно, но тогда он НЕ a unit test. Вместо этого вы выполняете интеграционный тест, который полезен для целей проверки требований и общей проверки работоспособности. Тестирование интеграции выполняется не так часто, как модульные тесты, на практике это делается в большинстве случаев, прежде чем переходить в избранное репозиторий кода, но не менее важно.
Единственное, что вам нужно иметь в виду, это следующее:
-
Mocks и stub предназначены для модульных тестов.
-
Реальные классы предназначены для интеграции/системных тестов.
Ответ 5
Используйте настоящую вещь только в том случае, если она сама тестировалась. Если он вводит зависимости, которые предотвращают это (круговые зависимости или если для этого требуются некоторые другие меры), используйте класс "mock" (обычно называемый "заглушкой" ).
Ответ 6
Извлечен и расширен из моего ответа. Как выполнить единичный тест наследующих объектов?" > здесь:
Вы всегда должны использовать реальные объекты, где это возможно.
Вы должны использовать только mock-объекты, если реальные объекты выполняют то, что вы не хотите настраивать (например, использовать сокеты, последовательные порты, получать пользовательский ввод, извлекать громоздкие данные и т.д.). По сути, имитирующие объекты относятся к тому, когда оцениваемая попытка реализовать и поддерживать тест с использованием реального объекта больше, чем для реализации и поддержания теста с использованием макетного объекта.
Я не покупаю аргумент "зависимого теста". Если тест терпит неудачу, потому что класс, от которого зависел, был сломан, тест сделал именно то, что он должен был сделать. Это не запах! Если изменился интерфейс зависимых, я хочу знать!
Высокоразвитые тестовые среды очень требуют обслуживания, особенно в начале проекта, когда интерфейсы находятся в потоке. Ive всегда находил, что лучше начать интеграционное тестирование как можно скорее.
Ответ 7
Если вам не нужно проверять ожидания относительно того, как ваш UnitUnderTest должен взаимодействовать с Thing, а взаимодействие с RealThing не имеет других побочных эффектов (или вы можете их издеваться), то, на мой взгляд, просто пусть ваш UnitUnderTest использует RealThing.
То, что тест затем покрывает больше вашей базы кода, является бонусом.
Я обычно считаю, что легко сказать, когда я должен использовать ThingMock вместо RealThing:
- Когда я хочу проверить ожидания во взаимодействии с Вещей.
- Использование RealThing приведет к нежелательным побочным эффектам.
- Или когда RealThing просто слишком сложно/затруднительно использовать в тестовой настройке.
Ответ 8
Я очень издевался над издеваемыми предметами, так как меня укусили их несколько раз. Они великолепны, когда вам нужны изолированные модульные тесты, но у них есть пара проблем. Основная проблема заключается в том, что если классу Order требуется коллекция объектов OrderItem, и вы издеваетесь над ими, то почти невозможно проверить, соответствует ли поведение издеваемого класса OrderItem реальному примеру (дублирование методов с соответствующими сигнатурами обычно не является достаточно). Не раз я видел, что системы терпят неудачу, потому что издевавшиеся классы не соответствуют реальным, и не было достаточно тестов интеграции, чтобы поймать крайние случаи.
Я вообще программирую на динамических языках, и я предпочитаю просто переопределять конкретные методы, которые являются проблематичными. К сожалению, это иногда трудно сделать на статических языках. Недостатком этого подхода является то, что вы используете интеграционные тесты, а не единичные тесты, а ошибки иногда сложнее отслеживать. Поверхность заключается в том, что вы используете фактический код, который написан, а не издеваемую версию этого кода.
Ответ 9
Если ваши "настоящие вещи" - это просто объекты ценности, такие как JavaBeans, тогда это прекрасно.
Для чего-то более сложного я бы волновался, поскольку издевки, созданные из насмешливых фреймворков, могут быть заданы точные ожидания относительно того, как они будут использоваться, например. количество вызванных методов, точную последовательность и ожидаемые параметры каждый раз. Ваши реальные объекты не могут сделать это для вас, поэтому вы рискуете потерять глубину в своих тестах.
Ответ 10
Если вы пишете свой код с точки зрения интерфейсов, то тестирование модулей становится радостью, потому что вы можете просто ввести поддельную версию любого класса в класс, который вы тестируете.
Например, если ваш сервер базы данных по какой-либо причине не работает, вы все равно можете провести модульное тестирование, написав поддельный класс доступа к данным, который содержит некоторые приготовленные данные, хранящиеся в памяти на карте хеширования или что-то в этом роде.
Ответ 11
Это зависит от вашего стиля , того, что вы делаете, опыта и других вещей.
Учитывая все это, вас не останавливает с помощью.
Я знаю, что слишком часто использую термин unit test. Большая часть того, что я делаю, может быть лучше названа интеграционным тестом, но все же лучше просто подумать об этом как о тестировании.
Поэтому я предлагаю использовать все методы тестирования, где они подходят. Общая цель хорошо протестировать, сделать малое время, сделать это и лично иметь твердое чувство , что это правильно.
Сказав, что в зависимости от того, как вы программируете, вы можете рассмотреть возможность использования методов (например, интерфейсов), которые немного глубже вторгаются. Но не используйте интерфейсы и инъекции там, где это неправильно. Также, если макет должен быть достаточно сложным, вероятно, меньше причин его использовать. (В ответах здесь вы найдете много хорошего руководства, что подходит, когда.)
Поставить другим способом: Ответ не всегда срабатывает. Держите свое остроумие в себе, наблюдайте, что работает, чего нет и почему.