Вопросы проектирования при включении модульного тестирования в приложении .Net? - PullRequest
4 голосов
/ 04 марта 2011

Все методы в .Net по умолчанию считаются окончательными, если не используется виртуальный модификатор. Ява наоборот. Все методы являются виртуальными и могут быть переопределены. Когда дело доходит до модульного тестирования с такими фреймворками, как Moq, RhinoMock и т. Д., Мы можем создать макет или заглушку. Если мы хотим создать макет, нам нужен интерфейс. Это заставляет нас использовать интерфейсы везде, если нет необходимости просто иметь возможность тестировать наш код.

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

Существуют и другие фальшивые фреймворки, использующие AOP, такие как TypeMock, но я не уверен, что смогу мотивировать тратить деньги на подобные фреймворки, когда есть такие хорошие открытые и бесплатные.

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

Итак, мой вопрос: должен ли почти все быть интерфейсом, даже если он на самом деле не инкапсулирует какое-то поведение? Или мы должны сделать виртуальные методы по мере необходимости, чтобы помочь нашему тестированию Оба чувствуют себя немного хакерскими и ненужными мне.

Что ты думаешь?

Ответы [ 3 ]

3 голосов
/ 04 марта 2011

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

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

(Это мнение делает меня несколько старомодным, я понимаю, но оно помогает мне понять мой дизайн, по крайней мере:)

2 голосов
/ 04 марта 2011

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

Создать интерфейс для класса действительно довольно просто, учитывая, что в Visual Studio даже есть необходимые встроенные параметры рефакторинга (щелчок правой кнопкой мыши, refactor-> extract interface). Таким образом, усилия по созданию интерфейса для создания интерфейса несколько тривиальны (при условии, что дизайн определяется тем, как класс выглядит в итоге).

Несмотря на то, что со временем поддерживаются некоторые интерфейсы, я использую их чаще, чем нет. Это уменьшает открытость интерфейса API, что упрощает обслуживание, и если у вас есть такие инструменты, как R #, то никаких дополнительных усилий почти не требуется.

Стоит также упомянуть, что TypeMock и Moles (компаньон Pex) оба подключаются к API профилирования. Как таковая, она несколько отличается от AOP, хотя и предоставляет возможности, подобные AOP. Они полезны, когда вам нужно перехватить статические методы или регулярные обращения к полям, то, что вы не можете моделировать с помощью интерфейсов.

0 голосов
/ 04 марта 2011

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

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

  1. верным или нет
  2. вам действительно нужно иметь возможность макетировать / заглушать элементы маркировки типа
  3. поскольку виртуальный будет вредить дизайну,
  4. представит интерфейс, помогающий дизайну

(я бы рассмотрел одновременно и 3, и 4)

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

Пересмешиваниеструктуры-заглушки, для которых не требуется интерфейс или виртуальный член: Typemock , Moles , и я считаю JustMock .Первые два используют API профилирования (и я полагаю, что JustMock тоже), которые по существу перенаправляют вызов метода куда-то еще, что вы определили.Есть некоторые споры о том, является ли возможность сделать это хорошей вещью, так как это может означать, что вам нужно меньше думать о дизайне, однако бывают случаи, когда это действительно может помочь (DateTime.Now - классический пример).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...