Проблема с NUnit при определении каталога сборки

Я только начал работать с NUnit, чтобы обеспечить тестовое покрытие для моих проектов.

В моей основной library.dll мне нужно загрузить данные конфигурации из внешнего файла, который идет вместе с библиотекой library.xml.

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

string settingspath = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);

Проблема, которую я заметил, заключается в том, что, когда я выполняю модульное тестирование с помощью NUnit, он копирует мои сборки в теневую копию, но не берет с собой другие файлы, поэтому, конечно, моя инициализация завершается неудачно из-за отсутствия файлов конфигурации,

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

7 ответов

Решение

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

Использование можно использовать TestContext.CurrentContext.TestDirectory как упоминал Чарли Пул из NUnit здесь:

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

NUnit не копирует никакие сборки: теневое копирование является функцией самого.NET. Следовательно, проблема должна рассматриваться как "Как я могу получить доступ к файлу, где он находится?" а не "Как я могу скопировать файл туда, где я думаю, что это должно быть?"

Есть три способа найти файл, который находится в том же каталоге, что и сборка:

1) Используйте Assembly.Codebase - это даст вам местоположение в качестве URI, которое вы должны затем преобразовать в соответствующий путь.

2) Используйте текущий каталог, который NUnit исторически установил в каталог, содержащий исполняющуюся тестовую сборку. Тем не менее, это может быть не так для будущих выпусков.

3) Используйте TestContext.CurrentContext.TestDirectory от NUnit, который доступен в самых последних выпусках.

Все эти подходы на самом деле используют Assembly.Codebase под прикрытием, а NUnit корректно преобразовывает URI в #2 и #3. Обычный подход к использованию Assembly.Location неверен, если только вы на самом деле не хотите определить местоположение кэша теневой копии.

Для использования справочных файлов в моих модульных тестах я использую Assembly.Codebase, которая работает, даже если включено теневое копирование. Возможно, вы захотите попробовать...

Он возвращает строку в формате Uri.. поэтому вам нужно создать экземпляр Uri из строки кодовой базы и использовать Uri.LocalPath, чтобы получить фактический путь к папке.

Однако для производственного кода BaseFolder должен быть извлечен из хорошо известного места (например, ключ реестра, установленный через установщик в Windows). Все поиски файлов должны быть укоренены из этого baseFolder.

Даже если теневое копирование активно, AppDomain.CurrentDomain.BaseDirectory указывает на исходное местоположение тестовых DLL.

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

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

Установлен ли внешний файл как часть сборки вашего dll? Если вы включите его в проект и установите его всегда копировать в "Копировать в вывод" в свойствах файла, то он должен перейти в теневую директорию, я думаю.

Это может помочь вам.

Мы включаем тестовый ресурс в тестовый проект (в данном случае в папку "TestData").

В Visual Studio для доступа к ресурсу в тестовой отметкеВ Visual Studio для доступа к ресурсу в тестовой отметке

Когда сборка проекта оставляет изображение в папке 'bin\Debug'Когда сборка проекта оставляет изображение в папке 'bin \ Debug

и ты пишешь путь

string fullImagePath = @".\TestData\vcredist.bmp";

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

У меня были дополнительные проблемы: во-первых, средство запуска графического интерфейса NUnit 2 не работает так же, как средство запуска графического интерфейса пользователя NUnit 3 (теперь оно называется TestCentric). Во-вторых, мне иногда нужно вызвать тестовые методы из другого исполняемого файла. Для справки, вот пути, которые я получаю:

NUnit 2:

AppDomain.CurrentDomain.BaseDirectory = @"C:\PathToNUnitProject\"
NUnit.Framework.TestContext.CurrentContext.WorkDirectory = @"C:\PathToNUnitProject"
NUnit.Framework.TestContext.CurrentContext.TestDirectory = @"C:\PathToNUnitProject\bin\Debug"

NUnit 3:

AppDomain.CurrentDomain.BaseDirectory = @"C:\PathToNUnitProject\bin\Debug\"
NUnit.Framework.TestContext.CurrentContext.WorkDirectory = @"C:\TestCentric\testcentric-gui-1.2.0"
NUnit.Framework.TestContext.CurrentContext.TestDirectory = @"C:\PathToNUnitProject\bin\Debug"

Когда тестовый метод вызывается извне NUnit:

AppDomain.CurrentDomain.BaseDirectory = something else entirely
NUnit.Framework.TestContext.CurrentContext.WorkDirectory = Exception
NUnit.Framework.TestContext.CurrentContext.TestDirectory = Exception

Для меня решение: использовать NUnit.Framework.TestContext.CurrentContext.TestDirectory, как в ответе Джеффа, в пределах попытки. Если это не сработает, возвращаемый путь будет одинаковым для обеих версий NUnit.

Столкнулся с той же проблемой... вот моя тренировка:

Перед запуском SUT обновите базовый каталог AppDomain следующим образом...

String root_path = "{{your path}}";
AppDomain.CurrentDomain.SetData("APPBASE", root_path);
Другие вопросы по тегам