Подтвердить что ты не робот

Почему так плохо издеваться над классами?

Недавно я обсуждал с коллегой насмешки. Он сказал, что насмешливые классы очень плохи и не должны делаться, только в немногих случаях.

Он говорит, что нужно обманывать только интерфейсы, иначе это ошибка архитектуры.

Интересно, почему это выражение (я полностью доверяю ему) настолько верно? Я не знаю этого и хочу быть уверенным.

Пропустил ли я насмешку (да, я читаю статья Мартина Фаулера)

4b9b3361

Ответ 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, нужно ли использовать их и когда их удалять.