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

Если вы только издеваетесь над типами, которыми владеете?

Я прочитал TDD: только макет типа, который у вас есть) в записи Марка Нидхема и хотел бы знать, является ли это лучшей практикой или нет?

Обратите внимание, что он не против насмешек, а против насмешек прямо - он говорит, что пишет обертку и насмехается, что все в порядке.

4b9b3361

Ответ 1

Зависит от того, означает ли вы mock или mock & trade; & hellip;

Учитывая, что вы просто используете фреймворк (например, Mockito) для создания заглушек, тогда создание заглушек типов, которыми вы не владеете, полностью в порядке и разумно.

Если, однако, вы используете фреймворк (например, Mockito) для создания макета и торговли; объекты, тогда вы лучше всего следуете советам макета и торговли; евангелисты. Лично я потерял связь с этим движением, поэтому я не могу сказать вам, следует ли считать совет Марка Нидхема кошерным или нет.

Ирония в сторону, то, что Марк пишет об издевательстве EntityManagers в Hibernate, звучит разумно сам по себе. Но я сомневаюсь, что мы можем обобщить правило, подобное "никогда не издевающимся типам, которые вы не владеете" из этого конкретного случая. Иногда это может иметь смысл, иногда нет.

Ответ 2

Мой ответ "нет". Вы должны издеваться над тем, что имеет смысл в контексте данного unit test. Не имеет значения, имеете ли вы "собственный" издеваемый тип или нет.

В наши дни в среде Java или .NET все (и я действительно имею в виду все) можно легко высмеять. Таким образом, нет никаких технических оснований для того, чтобы начать работу над написанием дополнительного кода оболочки.


Некоторые дополнительные идеи, о которых я думал недавно (ноябрь 2010 г.), которые показывают, насколько нелогичны "только макетные типы, которыми вы владеете", могут быть:

  • Предположим, вы создаете оболочку для стороннего API, а затем вы издеваетесь над оберткой в ​​модульных тестах. Позже, однако, вы видите, что оболочка может быть повторно использована в другом приложении, поэтому вы перемещаете ее в отдельную библиотеку. Итак, теперь оболочка больше не "принадлежит" вам (поскольку она используется в нескольких приложениях, которые могут поддерживаться разными командами). Должны ли разработчики создать новую оболочку для старой?!? И продолжайте делать это рекурсивно, добавив слой на слой практически бесполезного кода?
  • Предположим, что кто-то еще создал хороший обертку для некоторого нетривиального API и сделал его доступным как библиотека многократного использования. Если указанная оболочка - это то, что мне нужно для моего конкретного случая использования, я должен сначала создать оболочку для обертки с почти идентичным API, так что я буду "владеть" ею?!?

Для конкретного и реалистичного примера рассмотрите API Apache Commons Email, который является не чем иным, как оболочкой для стандартного API Java Mail. Поскольку я не владею им, должен ли я всегда создавать оболочку для Commons Email API, когда я пишу модульные тесты для класса, который должен отправлять электронную почту?

Ответ 3

Мне нравится описание которое проект Mockito дает на этот вопрос.

Не издевайтесь над типом, которым вы не владеете!

Это не жесткая линия, но пересечение этой строки может иметь последствия! (это, скорее всего, будет)

  • Представьте код, который издевается над третьей стороной lib. После определенного обновления третьей библиотеки логика может немного измениться, но тест Suite будет исполнять только штраф, потому что он издевался. Так позже, думая, что все хорошо, строительная стена зеленая, программное обеспечение развернуто и... Boom
  • Это может быть признаком того, что текущий дизайн не отделен от этой сторонней библиотеки.
  • Еще одна проблема заключается в том, что сторонняя библиотека может быть сложной и требует много макетов для нормальной работы. Это приводит к чрезмерному определенные тесты и сложные приборы, что само по себе компрометирует компактную и читаемую цель. Или к тестам, которые не охватывают код из-за сложности издеваться над внешней системой.

Вместо этого наиболее распространенным способом является создание оберток вокруг внешнего lib/system, хотя следует знать об опасности абстракции утечка, когда слишком много API низкого уровня, концепции или исключения, за границей обертки. Чтобы проверить интеграцию с третьей стороной библиотеки, написать интеграционные тесты и сделать их как можно компактнее и читабельнее.

Ответ 4

Я собирался сказать "нет", но, быстро взглянув на сообщение в блоге, я вижу, о чем он говорит.

Он говорит конкретно о насмешливых EntityManager в Hibernate. Я против этого. EntityManager должен быть скрыт внутри DAO (или аналогичных), и DAO - это то, что должно быть издевательством. Тестирование вызовов по одной строке EntityManager - полная трата вашего времени и будет ломаться, как только что-то изменится.

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

Ответ 5

Я, конечно, из меньшинства, но я отношусь к Mocking как запах кода и вместо этого использую инъекцию зависимости, если это возможно. Обоснование заключается в том, что издевательство - это, в основном, обходной путь для тестирования некоторых сложных тестов. Mocks ослабляет тесты, потому что они ведут себя (в лучшем случае), как определенная версия библиотеки. Если библиотека изменится, ваш тест потеряет все проверенное значение.

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

ОК, если инъекция зависимостей не является опцией, тогда пусть макет... но тогда вы должны понимать, что ваш тест является подделкой и не будет вести себя как производственный код. Это не настоящий unit test, а лишь частично фальшивый. Если возможно, вы можете сделать это меньше, добавив тесты, которые проверяют, что поведение соответствует ожидаемым для Mocked Objects.

Ответ 6

ИМХО, вопрос владения не имеет значения.

Соответствующий вопрос относится к сочетанию, т.е. Что указывает ваш тестовый код. Вы, конечно, не хотите, чтобы тестовый код указывал детали API некоторой библиотеки, которую вы использовали. Это то, что вы получаете, когда вы, например, используете Mockito, чтобы издеваться над библиотекой непосредственно в вашем тестовом классе.

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

  • Код внутри обертки не проверен.
  • Обертка может быть несовершенной абстракцией, поэтому API обертки, возможно, потребуется изменить. Если вы издевались над оберткой во многих тестах, вам нужно адаптировать все эти тесты.

Поэтому вместо этого я бы рекомендовал полностью отделить тесты от интерфейсов в продуктивном коде. Не помещайте mocks в тестовый код напрямую, но создайте отдельный класс заглушки, который реализует или издевается над продуктивным интерфейсом. Затем добавьте второй интерфейс к заглушке, который позволяет тестам выполнять необходимую настройку или утверждения. Затем вам нужно только адаптировать один класс в случае изменения производительного интерфейса, и вы даже можете позволить себе издеваться/заглушить интерфейс библиотеки, которая является сложной или часто меняет.


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

Ответ 7

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

Мое эмпирическое правило - это модные вещи, которые сделают тест быстрым, но не сделают тест неровным. Помните, что не все подделки одинаковы и Mocks не являются заглушками.