Развертывайте файлы вместе с тестами MSTest

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

Обзор

Когда вы применяете [DeploymentItem] к тестовому классу или методу теста, MSTest копирует указанные файлы или папки в каталог, доступный через TestContext.DeploymentDirectory, до запуска любого теста в этой области видимости. Каталог развертывания также является текущим рабочим каталогом для теста, поэтому тестовый код может открывать файлы по их скопированным именам.

Атрибут принимает относительный или абсолютный путь:

  • Относительные пути разрешаются относительно каталога выходных данных сборки (папки, содержащей тестовую сборку, например bin\Debug\net10.0\).
  • Абсолютные пути используются as-is.

Important

В MSTest 3.x элементы развертывания копируются для каждого запуска тестов. Чтобы сделать файл доступным во время развертывания, файл должен уже существовать в (или скопирован в) выходной каталог сборки.

Применять [DeploymentItem]

Атрибут может применяться к методу тестирования, классу тестирования или обоим. Допускается несколько вариантов, и они могут сочетаться:

using System.IO;
using Microsoft.VisualStudio.TestTools.UnitTesting;

[TestClass]
[DeploymentItem(@"TestFiles\shared-config.json")]
public class ConfigurationTests
{
    [TestMethod]
    [DeploymentItem(@"TestFiles\customers.csv")]
    public void LoadCustomers_FromCsv_ReturnsAllRows()
    {
        // Both shared-config.json (from the class) and customers.csv (from
        // the method) are available in the deployment directory.
        Assert.IsTrue(File.Exists("shared-config.json"));
        Assert.IsTrue(File.Exists("customers.csv"));
    }
}

Note

При применении [DeploymentItem] к тестовом классу класс должен содержать по крайней мере один метод теста. Применение этого к классу, который содержит только методы AssemblyInitialize или ClassInitialize, не оказывает никакого эффекта. Анализатор MSTEST0035 помечает такое некорректное использование.

Перегрузки конструктора

DeploymentItemAttribute имеет два конструктора: DeploymentItemAttribute(string path) и DeploymentItemAttribute(string path, string outputDirectory).

DeploymentItemAttribute(string path)

Копирует файл или папку, указанные в path, в корневой каталог развертывания.

// Copy a single file from the build output directory.
[DeploymentItem("settings.json")]

// Copy a file that lives in a subfolder of the build output directory.
// The file is copied to the root of the deployment directory (the
// "Resources" folder is not preserved).
[DeploymentItem(@"Resources\test-data.xml")]

// Copy the entire TestFiles folder (and all of its subfolders) into the
// deployment directory.
[DeploymentItem("TestFiles")]

DeploymentItemAttribute(string path, string outputDirectory)

Копирует элементы в подкаталог каталога развертывания, заданный в outputDirectory.

// Creates a "Data" subfolder under the deployment directory, then copies
// test-data.xml into it. The file is reached at "Data\test-data.xml".
[DeploymentItem("test-data.xml", "Data")]

// Copies the contents of the Resources folder into a "Resources"
// subfolder of the deployment directory.
[DeploymentItem("Resources", "Resources")]

Аргумент outputDirectory должен быть путем к папке. Его нельзя использовать для переименования файла. Чтобы развернуть файл с другим именем, переименуйте его в исходной папке (или используйте шаг после сборки).

Обеспечение доступа исходных файлов к выходному каталогу сборки

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

Используйте <None> или <Content> с CopyToOutputDirectory

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

<ItemGroup>
  <None Update="TestFiles\**\*.*">
    <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
  </None>
</ItemGroup>

После сборки папка TestFiles копируется в bin\<Configuration>\<TargetFramework>\TestFiles\, и [DeploymentItem("TestFiles")] корректно разрешается.

Использование целевого объекта после сборки

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

<Target Name="CopySharedAssets" AfterTargets="Build">
  <Copy SourceFiles="@(SharedAsset)"
        DestinationFolder="$(OutDir)SharedAssets\" />
</Target>

Проверьте каталог развертывания во время выполнения

Если вам нужен абсолютный путь к каталогу развертывания — например, чтобы передать его запускаемому процессу или записать его в журнал для диагностики, — используйте TestContext.DeploymentDirectory:

using System.IO;

[TestMethod]
[DeploymentItem(@"TestFiles\input.json")]
public void ProcessInput_FromDeployedFile_Succeeds()
{
    string fullPath = Path.Combine(TestContext.DeploymentDirectory, "input.json");
    string contents = File.ReadAllText(fullPath);
    // ...
}

Дополнительные сведения о TestContext см. в разделе Класс TestContext.

Если развертывание не происходит

По умолчанию MSTest создает каталог развертывания для каждого запуска и копирует в него элементы. Вы можете отключить развертывание в .runsettings файле, чтобы тесты выполнялись непосредственно из выходного каталога сборки:

<RunSettings>
  <MSTest>
    <DeploymentEnabled>False</DeploymentEnabled>
  </MSTest>
</RunSettings>

Если развертывание отключено, атрибуты [DeploymentItem] не действуют, и тест выполняется непосредственно в выходном каталоге сборки. Дополнительные параметры конфигурации см. в разделе "Настройка MSTest".

Устаревший режим и .testsettings

Когда MSTest работает в устаревшем режиме (используется файл .testsettings или в файле .runsettings для RunSettings/MSTest/ForcedLegacyMode задано значение true), относительные пути могут разрешаться относительно корневого каталога решения, а не каталога выходных данных сборки. Избегайте устаревшего режима в новых проектах — рекомендуемым подходом является современная конфигурация на основе .runsettings.

Лучшие практики

  • Предпочитайте CopyToOutputDirectory вместо глубоких относительных путей. Не обращайтесь к папкам с исходным кодом, используя пути в стиле ..\..\ — они привязывают ваши тесты к определённой структуре репозитория. Сначала настройте файлы в выходном каталоге сборки.
  • Делайте элементы развертывания небольшими. Каждый элемент копируется для каждого тестового запуска; большие файлы замедляют выполнение теста.
  • Используйте папки для совместного развертывания связанных ресурсов. [DeploymentItem("TestFiles")] проще поддерживать, чем десятки атрибутов для каждого файла.
  • Предпочитайте внедренные ресурсы или данные в памяти для небольших светильников. Внедренные ресурсы устраняют необходимость развертывания и избегают ввода-вывода во время тестирования.
  • Не полагайтесь на то, что рабочий каталог является каталогом проекта. Во время тестирования рабочий каталог является каталогом развертывания, а не папкой тестового проекта.

См. также