2015-08-28 1 views
4

Когда класс реализует интерфейс, тогда его легко насмехаться, но для этого вам нужно создать интерфейс.Почему интерфейсные Mocks более желательны, чем подклассы Mocks при модульном тестировании?

Вы также можете макетировать путем подклассификации и переопределения. Если ваш базовый класс предоставляет конструктор без параметров, то ваши подклассы mocks не привязаны к изменениям в конструкторе базового класса.

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

Итак, почему издевательства на основе интерфейсов считаются лучшей практикой, чем издевательствами на основе подкласса?

+0

Странный вопрос, который необходимо задать в 2015 году, поскольку каждая из насмешливая библиотека уже много лет поддерживает первоклассную поддержку насмешек. И, насколько я знаю и, по крайней мере, в сообществе Java, только один из разработчиков jMock на самом деле побуждал пользователей издеваться над интерфейсами; другие разработчики Java-шуток не настаивали на этом. –

+1

Я не думаю, что это странно, если вы не используете насмешливую библиотеку. При этом я определенно хотел бы использовать библиотеку для издевательства над конкретными классами, чем создавать интерфейсы только для тестирования. – jrahhali

ответ

5

В отличие от большинства убеждений, даже если вы проводите тестирование (TDD), вам следует следовать хорошей практике проектирования. Трюк состоит в том, чтобы сделать тестируемые API и хорошо продуманными. TDD isn't a design methodology, но метод обратной связи.

Таким образом, это не вопрос интерфейс Mocks против Подкласса издевается, а скорее вопрос интерфейсов по сравнению с подклассами.

Это действительно старая дискуссия, которая должна была закончиться в 1994 году; в Design Patterns, мы узнаем, что мы должны поддерживать композицию над наследованием.

Существует длинная дискуссия по этой теме, но вкратце, на языках с одним наследованием, основываясь на дизайне API на наследование, необходимо ограничить всю будущую изменчивость по другим (но непредвиденным) размерам. Наследование на таких языках просто слишком ограничительно. Поскольку все основные объектно-ориентированные языки (Java, C#, Ruby) имеют единое наследование, вы должны видеть, что большинство объектно-ориентированных кодовых баз правильно избегают наследования.

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

+0

Я изо всех сил пытаюсь понять этот ответ ... «Композиция над наследованием» заключается не в использовании отдельных интерфейсов, а просто в использовании объекта типа A изнутри объекта типа B вместо того, чтобы наследовать B от A. Для конкретный пример, рассмотрим Java-класс 'java.util.Properties', который был (неправильно) разработан с наследованием класса' java.util.Hashtable', когда он должен был просто * использовать * 'Hashtable' внутри. –

+0

@ Rogério Достаточно честный; в моем ответе есть несколько неявных предположений, которые могли бы быть более явными. Мое использование слова * Композиция * сильно приправлено [Шаблоны проектирования] (http://amzn.to/XBYukB), в котором говорится (стр. 19), что «Состав объекта определяется динамически во время выполнения через ссылки на объекты к другим объектам. Композиция требует, чтобы объекты уважали интерфейсы друг друга ». Когда вы следуете принципам, изложенным в шаблонах проектирования, на языке единого наследования, наследование исключается, поэтому интерфейс должен быть. –

+0

Да, но обратите внимание, что вопрос касается [* отделенных * интерфейсов] (http://martinfowler.com/eaaCatalog/separatedInterface.html), а не общей концепции интерфейса, используемой в книге для «композиции над наследованием», принцип. Я не говорю, что в этом принципе есть что-то не так, просто для того, чтобы он не разделял интерфейс. В моем Java-примере класс 'Properties' мог/должен иметь/должен иметь личное поле типа' Hashtable' (ну, ok, 'java.util.Dictionary', если следовать принципу * другого * из книги, один о «коде для интерфейса, а не о реализации»). –

2

Когда вы подтип и переопределяете, у вас есть риск потерять переопределение одного из методов, которые вы должны переопределить, и фактически запустить «производственный» код, который вы хотите изолировать от своего теста.

Когда вы издеваетесь над интерфейсом, 100% его поведения должно быть издевательством. Независимо от того, что явно не указано, насмехаясь, просто выкинет исключение и заставит вас обратиться к нему.

+0

Это не то, чем насмехаются библиотеки. Они не будут генерировать исключение для методов, не «явно заявленных насмешкой», если только это не * * * макет. Но каждая насмешливая библиотека позволяет пользователю выбирать между строгой и нестрогой проверкой, поэтому это всегда под контролем пользователя. И, конечно же, это в равной степени относится к издевательствам интерфейсов * и * классов. –

+1

@ Rogério, но вопрос был не в сравнении строгого строения с нестрогой проверкой.Речь шла о подклассификации и переопределении себя (по крайней мере, насколько я понял) – Mureinik

+1

Я думаю, что это остроконечный ответ на вопрос. @Mureinik определенно указал на некоторые недостатки подкласса. – jrahhali

Смежные вопросы