C# - исключение модульных тестов из релизной версии вашего проекта

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

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

Одно решение, которое я нашел, - заключить все ваши модульные тесты в директивы #if DEBUG - #endif: когда код не ссылается на сборку модульного тестирования, компилятор достаточно умен, чтобы опустить ссылку в скомпилированном коде.

Есть ли другие (возможно, более удобные) варианты достижения подобной цели?

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
24
0
8 527
13
Перейти к ответу Данный вопрос помечен как решенный

Ответы 13

Ответ принят как подходящий

Я определенно рекомендую выделить ваши тесты в отдельный проект. На мой взгляд, это единственный выход.

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

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

Garry Shutler 17.09.2008 14:46

Я бы также порекомендовал другую структуру папок. ProjName \ Code \ SubPackage и ProjName \ Tests \ SubPackage.

Gishu 17.09.2008 15:16

Что делать, если вам нужен whitebox-тест?

Roman Plášil 02.07.2010 14:42

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

Joel in Gö 15.02.2011 13:22

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

Для каждого проекта существует соответствующий тестовый проект, содержащий тесты.

Например. для сборки с именем, скажем, «Acme.BillingSystem.Utils», должна быть тестовая сборка с именем «Acme.BillingSystem.Utils.Test».

Исключите ее из поставляемой версии продукта, не отправляя эту dll.

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

Поддержание параллельных пространств имен и использование разумного соглашения об именах для тестов (например, MyClass и MyClassTest) поможет вам сохранить кодовую базу поддерживаемой.

Инфраструктура .Net после версии 2 имеет полезную функцию, позволяющую пометить сборку атрибутом InternalsVisibleTo, который позволяет другой сборке получить доступ к ней. Этакая сборочная функция туннелирования.

Как отмечают другие, отдельный тестовый проект (для каждого нормального проекта) - хороший способ сделать это. Обычно я зеркалирую пространства имен и создаю тестовый класс для каждого нормального класса с добавлением «test» к имени. Это поддерживается непосредственно в IDE, если у вас есть Visual Studio Team System, которая может автоматически создавать тестовые классы и методы в другом проекте.

Одна вещь, которую следует запомнить, если вы хотите протестировать классы и методы с «внутренним» аксессором, - это добавить следующую строку в файл AssemblyInfo.cs для каждого проекта, который нужно протестировать:

[assembly: InternalsVisibleTo("UnitTestProjectName")]

Спасибо также! Это значит, что мы можем перестать публиковать информацию ради ура тестов! : D

Sam Wessel 23.09.2008 17:50

Если вы присваиваете своим сборкам строгое имя (как и следовало бы), вам также необходимо добавить в объявление длинную строку открытого ключа. Примечание: строгое именование не является защитой от сторонней связи с внутренними компонентами, поскольку к ним по-прежнему можно получить доступ через отражение.

Steve Gilham 12.08.2009 14:01

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

#if TEST
#endif

сначала, чтобы убедиться, что тестовый код не компилируется в производственном сценарии. Как только это будет сделано, вы сможете либо исключить тестовые библиотеки DLL из своего производственного развертывания, либо, что еще лучше (но с более высоким уровнем обслуживания), создать NAnt или MSBuild для производства, который компилируется без ссылок на тестовые библиотеки DLL.

Пока ваши тесты находятся в отдельном проекте, тесты могут ссылаться на кодовую базу, но кодовая база никогда не должна ссылаться на тесты. Я должен спросить, что сбивает с толку в сопровождении двух проектов? Вы можете оставить их в одном решении для организации.

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

Я всегда создаю отдельный проект Acme.Stuff.Test, который компилируется отдельно.

Обратный аргумент: почему вы хотите сдать тесты? Почему бы не сдать тест? Если вы доставляете тесты вместе с исполнителем тестов, у вас есть некоторый уровень приемочного тестирования и самотестирования, поставляемых вместе с продуктом.

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

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

Еще одна альтернатива использованию директив компилятора в файле или созданию отдельного проекта - это просто создание дополнительных файлов .cs в вашем проекте.

С помощью магии в самом файле проекта вы можете продиктовать следующее:

  1. Библиотеки DLL nunit.framework упоминаются только в отладочной сборке, и
  2. ваши тестовые файлы включены только в отладочные сборки

Пример отрывка из .csproj:

<Project DefaultTargets = "Build" xmlns = "http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion = "3.5">

   ...

   <Reference Include = "nunit.framework" Condition = " '$(Configuration)'=='Debug' ">
      <SpecificVersion>False</SpecificVersion>
      <HintPath>..\..\debug\nunit.framework.dll</HintPath>
   </Reference>

   ...

   <Compile Include = "Test\ClassTest.cs" Condition = " '$(Configuration)'=='Debug' " />

   ...
</Project>

Еще предстоит принять во внимание одну вещь: в версиях VisualStudio до 2005 года нельзя было ссылаться на проекты сборки EXE из других проектов. Итак, если вы работаете над унаследованным проектом в VS.NET, ваши варианты будут следующими:

  • Поместите модульные тесты в один и тот же проект и используйте условную компиляцию, чтобы исключить их из сборок выпуска.
  • Переместите все в сборки dll, чтобы ваш exe был просто точкой входа.
  • Обойти IDE, взломав файл проекта в текстовом редакторе.

Из трех условная компиляция наименее подвержена ошибкам.

Если тег #if (ОТЛАДКА) допускает чистую «релизную» версию, зачем вам нужен отдельный проект для тестов. Пример nunit LibarryA / B (да, я знаю его пример) делает это. В настоящее время борюсь со сценарием. Использовал отдельный проект, но, похоже, это, возможно, позволит улучшить производительность. По-прежнему хуммин и хавин.

Другие вопросы по теме