某些测试在运行时需要额外的文件,例如测试数据、配置文件、基准文件或原生依赖项。 使用 DeploymentItemAttribute 指定在每次测试运行时应在测试程序集旁可用的文件和文件夹。
概述
将 [DeploymentItem] 应用于测试类或测试方法时,MSTest 会在该范围内的任何测试运行之前,将指定的文件或文件夹复制到 TestContext.DeploymentDirectory 所指示的目录中。 部署目录也是测试的当前工作目录,因此测试代码可以通过复制的名称打开文件。
该属性接受相对路径或绝对路径:
-
相对路径是相对于构建输出目录(包含测试程序集的文件夹,例如
bin\Debug\net10.0\)解析的。 - 绝对路径将按原样使用。
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"));
}
}
注释
将 [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")]比数十个文件级属性更易于维护。 - 对于小型测试夹具,优先使用嵌入式资源或内存中的数据。 嵌入式资源无需部署,并在测试时避免 I/O。
- 不要依赖于工作目录作为项目目录。 在测试执行期间,工作目录是部署目录,而不是测试项目文件夹。