Почему так плохо издеваться над классами?
Недавно я обсуждал с коллегой насмешки. Он сказал, что насмешливые классы очень плохи и не должны делаться, только в немногих случаях.
Он говорит, что нужно обманывать только интерфейсы, иначе это ошибка архитектуры.
Интересно, почему это выражение (я полностью доверяю ему) настолько верно? Я не знаю этого и хочу быть уверенным.
Пропустил ли я насмешку (да, я читаю статья Мартина Фаулера)
Ответы
Ответ 1
Mocking используется для тестирования протокола - он проверяет, как вы будете использовать API, и как вы будете реагировать, когда API реагирует соответствующим образом.
В идеале (во многих случаях, по крайней мере) этот API должен быть указан как интерфейс, а не класс - интерфейс определяет протокол, класс определяет хотя бы часть реализации.
С практической точки зрения, насмешливые рамки, как правило, имеют ограничения в отношении насмешливых классов.
По моему опыту, насмешка несколько запутана - часто вас не интересует точное взаимодействие, вы действительно хотите заглушку... но насмешливую структуру можно использовать для создания заглушек, и вы попадаете в ловушку создания хрупкие тесты, насмешливые, вместо того, чтобы стучать. Это жесткий баланс, чтобы получить право, хотя.
Ответ 2
ИМХО, что означает ваш коллега, заключается в том, что вы должны программировать интерфейс, а не реализацию. Если вы слишком часто находите насмешливые классы, это знак, который вы нарушили предыдущий принцип при проектировании вашей архитектуры.
Ответ 3
Измерительные классы (в отличие от насмешливых интерфейсов) плохи, потому что у макета все еще есть реальный класс в фоновом режиме, он унаследован от, и возможно, что реальная реализация выполняется во время теста.
Когда вы издеваетесь над интерфейсом (или заглушкой или каким-либо другим), нет никакого риска выполнить код, который вы действительно хотели высмеять.
Изношенные классы также заставляют вас сделать все, что можно было бы издеваться, быть virtual, что очень навязчиво и может привести к плохому дизайну классов.. p >
Если вы хотите разделить классы, они не должны знать друг друга, это причина, по которой имеет смысл высмеивать (или заглушку или что-то еще) одно из них. Так что в любом случае рекомендуется применять против интерфейсов, но это упоминается здесь другими.
Ответ 4
Как правило, вы хотите издеваться над интерфейсом.
В то время как можно высмеять обычный класс, он слишком сильно влияет на дизайн вашего класса для проверки. Обеспокоенность, как доступность, независимо от того, является ли метод виртуальной и т.д., Будет определяться умением издеваться над классом, а не с истинными проблемами OO.
Существует одна ложная библиотека под названием TypeMock Isolator, которая позволяет обойти эти ограничения (есть торт, есть торт), но это довольно дорого. Лучше спроектировать для проверки.
Ответ 5
Я предлагаю держаться подальше от насмешливых фреймворков, насколько это возможно. В то же время я бы рекомендовал использовать макет/поддельные объекты для тестирования, насколько это возможно. Трюк здесь заключается в том, что вы должны создавать встроенные поддельные объекты вместе с реальными объектами. Я объясняю это более подробно в сообщении в блоге, которое я написал об этом: http://www.yegor256.com/2014/09/23/built-in-fake-objects.html
Ответ 6
Изменить. Поскольку вы уточнили, что ваш коллега означал, что mock класс плохой, но mock интерфейс не указан, ответ ниже устарел. Вы должны обратиться к этому ответу.
Я говорю о mock и stub как определенном Мартином Фаулером, и я предполагаю, что это означал и ваш коллега.
Отказывание плохо, потому что это может привести к чрезмерной проверке тестов. Используйте заглушку, если это возможно, и избегайте макета.
Здесь разница между mock и заглушкой (из вышеприведенной статьи):
Затем мы можем использовать проверку состояния на такой как заглушка.
class OrderStateTester...
public void testOrderSendsMailIfUnfilled() {
Order order = new Order(TALISKER, 51);
MailServiceStub mailer = new MailServiceStub();
order.setMailer(mailer);
order.fill(warehouse);
assertEquals(1, mailer.numberSent());
}
Конечно, это очень простой тест - только сообщение отправлено. Мы не протестировали его, отправив право человека или с правом содержимое, но это будет показано, чтобы проиллюстрировать точка.
Использование mocks этот тест будет выглядеть вполне отличается.
class OrderInteractionTester...
public void testOrderSendsMailIfUnfilled() {
Order order = new Order(TALISKER, 51);
Mock warehouse = mock(Warehouse.class);
Mock mailer = mock(MailService.class);
order.setMailer((MailService) mailer.proxy());
mailer.expects(once()).method("send");
warehouse.expects(once()).method("hasInventory")
.withAnyArguments()
.will(returnValue(false));
order.fill((Warehouse) warehouse.proxy());
}
}
Чтобы использовать проверку состояния на заглушке, мне нужно сделать некоторые дополнительные методы нa > заглушке, чтобы помочь с проверкой. В результате заглушка реализует MailService, но добавляет дополнительные > методы тестирования.
Ответ 7
Ответ, как и большинство вопросов о практике, "зависит от этого".
Чрезмерное использование макетов может привести к испытаниям, которые на самом деле ничего не тестируют. Это также может привести к испытаниям, которые являются виртуальными повторными реализациями тестируемого кода, тесно связанными с конкретной реализацией.
С другой стороны, разумное использование макетов и заглушек может привести к единичным тестам, которые аккуратно изолированы и проверять одно и только одно - это хорошо.
Все о модерации.
Ответ 8
Имеет смысл размахивать классами, поэтому тесты могут быть написаны на раннем этапе жизненного цикла разработки.
Существует тенденция продолжать использовать макетные классы, даже когда становятся доступными конкретные реализации. Существует также тенденция к разработке против ложных классов (и заглушек), необходимых в начале проекта, когда некоторые части системы не были построены.
После того как часть системы была построена, необходимо протестировать ее и продолжить проверку против нее (для регрессии). В этом случае, начиная с mocks, это хорошо, но их следует отбросить в пользу реализации как можно скорее. Я видел проекты борьбы, потому что разные команды продолжают развиваться против поведения макета, а не реализации (после его появления).
При тестировании на макеты вы предполагаете, что макет характерен для системы. Часто это предполагает угадывание того, что будет делать издевательский компонент. Если у вас есть спецификация системы, которую вы издеваетесь, вам не нужно угадывать, но часто система "as-built" не соответствует исходной спецификации из-за практических соображений, обнаруженных во время строительства. Гибкие проекты разработки предполагают, что это всегда произойдет.
Затем вы разрабатываете код, который работает с макетом. Когда выясняется, что макет действительно не отражает поведение реальной встроенной системы (например, проблемы с задержкой, которые не наблюдаются в проблемах с макетами, ресурсами и эффективностью, которые не наблюдаются в макетах, проблемах concurrency, проблемах производительности и т.д.), у вас тогда есть куча бесполезных дразнящих тестов, которые вы должны теперь поддерживать.
Я считаю, что использование макетов ценно в начале разработки, но эти издевательства не должны способствовать охвату проекта. Лучше всего позже, если издевки удаляются, и для их замены создаются правильные интеграционные тесты, иначе ваша система не будет тестироваться на множество условий, которые ваш макет не имитировал (или имитирует неправильно относительно реальной системы).
Итак, вопрос заключается в том, следует ли использовать mocks, нужно ли использовать их и когда их удалять.