Использование "дружеских" -декуляций для модульного тестирования. Плохая идея?

[Конечно, вопрос не ограничивается конкретной реализацией "друга", не стесняйтесь указывать на специфику реализации, если это необходимо]

Прочитав оставшиеся без ответа вопросы, я наткнулся на атрибут InternalsVisibleTo:

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

Руководство по программированию на С# на MSDN имеет раздел Friend Assemblies, описывающий, как использовать этот атрибут, чтобы использовать методы и типы internal для другой сборки.

Мне интересно, будет ли это хорошая идея использовать это для создания "скрытого" интерфейса для инструментария библиотеки для использования модульной тестовой сборкой. По-видимому, он значительно увеличивает связь в обоих направлениях (код тестирования в сборочной единице, интимные внутренние знания о сборке в тестовом коде), но, с другой стороны, это может помочь в создании мелкозернистых тестов без загромождения открытого интерфейса.

Каков ваш опыт использования объявлений друзей при тестировании? Это была ваша Серебряная пуля, или она начала Марш смерти?

Ответ 1

Я широко использовал этот метод - это означает, что мои модульные тесты могут тестировать аспекты библиотеки кода, которые не видны обычным потребителям.

При использовании [InternalsVisibleTo] увеличивается сцепление, я считаю, что (незначительное) увеличение хорошо стоит.

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

Иными словами, связь минимальна - с атрибутом [InternalsVisibleTo] в сборке кода и при маркировке некоторых вещей как внутри вместо private ( или защищенный внутренний вместо защищенный).

(Обратите внимание, что я игнорирую здесь любые изменения дизайна, которые вызваны использованием Unit Testing, что является целым другим обсуждением.)

Атрибут [InternalsVisibleTo] требует сильного именования ваших сборок. Если вы этого еще не делаете, вы можете найти это немного обременительным, поскольку сборка с сильной именованием может зависеть только от других сильно названных сборок, что может закончиться тем, что вам нужно изменить несколько сборок.

Получение правильного атрибута может быть немного затруднительным, поскольку он должен включать открытый ключ вашей тестовой сборки. У IDesign есть полезный инструмент для сборки Friend, который создает атрибут в вашем буфере обмена, готовый для вставки. Рекомендуется.

Ответ 2

Это единственное, что я когда-либо лично применял к InternalsVisibleTo - и это было очень и очень удобно.

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

Ответ 3

Я думаю, что использование InternalsVisibleToAttribute для модульного тестирования вполне разумно. Мой "блок" в "модульном тестировании" является классом и включает классы internal, поэтому я хочу их протестировать. Я не хочу использовать методы unit test private.

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

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

Ответ 4

Фактически, Unit Testing - единственное использование, которое я смог заставить использовать InternalsVisibleToAttribute для. При этом вы можете реализовать большую часть ваших методов 'private' как внутреннюю, а не подвергать их оболочке тестирования модулей для более инвазивного тестирования внутренних инвариантов класса.

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

Ответ 5

Я думаю, что еще один законный случай использования приходит, когда вы использовали отдельные сборки при объединении старого кода С++ с новым кодом С#.

Мы собрали сборки С++, конвертировали их в С++/CLI, а затем реализовали более новый код на С#. Когда мы это сделаем, мы все равно будем использовать "внутренние" для классов/методов на С#, которые на самом деле не являются общедоступными, а затем сделать их доступными для устаревшего кода в виде сборок для друзей.