MSTest 使用自定义属性来标识和自定义测试。
为了帮助提供更清晰的测试框架概述,本部分将 Microsoft.VisualStudio.TestTools.UnitTesting 命名空间的成员组织为相关功能组。
注意
名称以“Attribute”结尾的属性在使用时可以添加或不添加该“Attribute”后缀。 包含无参数构造函数的属性在写入时可以添加或不添加括号。 以下代码示例的工作方式相同:
[TestClass()]
[TestClassAttribute()]
[TestClass]
[TestClassAttribute]
用于标识测试类和方法的属性
每个测试类都必须具有 TestClass
属性,每个测试方法都必须具有 TestMethod
属性。
TestClassAttribute
TestClass 属性用于标记类,该类包含测试和可选的初始化或清理方法。
可以扩展此属性来改变或扩展默认行为。
示例:
[TestClass]
public class MyTestClass
{
}
TestMethodAttribute
TestMethod 属性在 TestClass
内用于定义要运行的实际测试方法。
该方法应该是定义为 public
、void
或 Task
的实例 ValueTask
方法(从 MSTest v3.3 开始)。 它可以是 async
,但不能是 async void
。
除非该方法使用 DataRow 属性、DynamicData 属性或向测试方法提供测试用例数据的类似属性进行标记,否则该方法应具有零个参数。
考虑以下示例测试类:
[TestClass]
public class MyTestClass
{
[TestMethod]
public void TestMethod()
{
}
}
用于数据驱动的测试的属性
使用以下元素设置数据驱动的测试。 有关详细信息,请参阅创建数据驱动的单元测试和使用配置文件定义数据源。
小窍门
MSTest 本身不支持组合测试,但可以使用开源 Combinatorial.MSTest NuGet 包添加此功能。 它由社区积极维护 ,并在 GitHub 上提供。 此包不受Microsoft维护。
DataRowAttribute
使用 DataRow 属性,可以使用多个不同的输入运行相同的测试方法。 它可以在测试方法上出现一次或多次。 它应与 TestMethod 属性结合使用。
参数的数量和类型必须与测试方法签名完全匹配。 请考虑以下示例,这是一种有效测试类,展示了如何使用 DataRowAttribute 来处理与测试方法参数相匹配的内联参数:
[TestClass]
public class TestClass
{
[TestMethod]
[DataRow(1, "message", true, 2.0)]
public void TestMethod1(int i, string s, bool b, float f)
{
// Omitted for brevity.
}
[TestMethod]
[DataRow(new string[] { "line1", "line2" })]
public void TestMethod2(string[] lines)
{
// Omitted for brevity.
}
[TestMethod]
[DataRow(null)]
public void TestMethod3(object o)
{
// Omitted for brevity.
}
[TestMethod]
[DataRow(new string[] { "line1", "line2" }, new string[] { "line1.", "line2." })]
public void TestMethod4(string[] input, string[] expectedOutput)
{
// Omitted for brevity.
}
}
注意
还可以使用 params
功能捕获 DataRowAttribute 的多个输入。
[TestClass]
public class TestClass
{
[TestMethod]
[DataRow(1, 2, 3, 4)]
public void TestMethod(params int[] values) {}
}
无效组合的示例:
[TestClass]
public class TestClass
{
[TestMethod]
[DataRow(1, 2)] // Not valid, we are passing 2 inline data but signature expects 1
public void TestMethod1(int i) {}
[TestMethod]
[DataRow(1)] // Not valid, we are passing 1 inline data but signature expects 2
public void TestMethod2(int i, int j) {}
[TestMethod]
[DataRow(1)] // Not valid, count matches but types do not match
public void TestMethod3(string s) {}
}
注意
从 MSTest v3 开始,当想要传递恰好 2 个数组时,不再需要将第二个数组包装在对象数组中。
此前:[DataRow(new string[] { "a" }, new object[] { new string[] { "b" } })]
从 v3 开始:[DataRow(new string[] { "a" }, new string[] { "b" })]
可以通过设置 DataRowAttribute 属性来修改 Visual Studio 中使用的显示名称以及每个 DisplayName 实例的记录器。
[TestClass]
public class TestClass
{
[TestMethod]
[DataRow(1, 2, DisplayName = "Functional Case FC100.1")]
public void TestMethod(int i, int j) {}
}
还可以通过继承 DataRow
来创建自己的专用 DataRowAttribute 属性。
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
public class MyCustomDataRowAttribute : DataRowAttribute
{
}
[TestClass]
public class TestClass
{
[TestMethod]
[MyCustomDataRow(1)]
public void TestMethod(int i) {}
}
用于提供初始化和清理的属性
可将多个测试共有的设置和清理提取到单独的方法中,并使用下面列出的属性之一进行标记,以便在适当的时间运行该方法,例如在每次测试之前。 有关详细信息,请参阅单元测试的剖析。
程序集级别
加载程序集后立即调用 AssemblyInitialize 属性,并在卸载程序集之前直接调用 AssemblyCleanup 属性。
用这些属性标记的方法应定义为 static void
、static Task
或 static ValueTask
(以 MSTest v3.3 开头),在标记为 TestClassAttribute的类中只显示一次。 初始化部分需要一个类型为 TestContext 的参数,而清理可以没有参数,或者从 MSTest 3.8 开始,可以有一个类型为 TestContext的参数。
[TestClass]
public class MyTestClass
{
[AssemblyInitialize]
public static void AssemblyInitialize(TestContext testContext)
{
}
[AssemblyCleanup]
public static void AssemblyCleanup() // Starting with MSTest 3.8, it can be AssemblyCleanup(TestContext testContext)
{
}
}
类级别
ClassInitialize 属性在加载类之前(但在静态构造函数之后)调用,ClassCleanup 在卸载类后立即调用。
重要
默认情况下,ClassCleanupAttribute 将在程序集的最后一次测试后触发(类似于 AssemblyCleanupAttribute)。 可以通过在属性上设置 CleanupBehavior 来更改此行为。 或者,可以使用程序集属性 ClassCleanupExecutionAttribute全局设置此行为。
还可以控制继承行为:仅适用于使用 InheritanceBehavior.None的当前类,或者对于使用 InheritanceBehavior.BeforeEachDerivedClass的所有派生类。
用这些属性标记的方法应在 static void
中定义为 static Task
、static ValueTask
或 TestClass
(从 MSTest v3.3 开始),并且只能出现一次。 初始化部分需要一个类型为 TestContext 的参数,而清理可以没有参数,或者从 MSTest 3.8 开始,可以有一个类型为 TestContext的参数。
[TestClass]
public class MyTestClass
{
[ClassInitialize]
public static void ClassInitialize(TestContext testContext)
{
}
[ClassCleanup]
public static void ClassCleanup() // Starting with MSTest 3.8, it can be ClassCleanup(TestContext testContext)
{
}
}
测试级别
在测试开始之前,TestInitialize 属性调用,测试完成后立即调用 TestCleanup。
TestInitializeAttribute 类似于类构造函数,但通常更适合长初始化或异步初始化。 TestInitializeAttribute 始终在构造函数后调用,并为每个测试调用(包括 数据驱动测试的每个条目)。
TestCleanupAttribute 类似于 Dispose
(或 DisposeAsync
)类,但通常更适合长时间或异步清理。
TestCleanupAttribute 始终在 DisposeAsync
/Dispose
之前调用,并为每个测试调用(包括 数据驱动测试的每个条目)。
用这些属性标记的方法应在 void
中定义为 Task
、ValueTask
或 TestClass
(从 MSTest v3.3 开始),不带参数,并且可以出现一次或多次。
[TestClass]
public class MyTestClass
{
[TestInitialize]
public void TestInitialize()
{
}
[TestCleanup]
public void TestCleanup()
{
}
}
用于控制测试执行的属性
以下属性可用于修改测试的执行方式。
TimeoutAttribute
Timeout 属性可用于指定测试方法允许运行的最长时间(以毫秒为单位)。 如果测试方法的运行时间超过指定时间,则测试将中止并标记为失败。
此属性可应用于任何测试方法或任何固定例程方法(初始化和清理方法)。 还可以使用 runsettings 文件的 timeout 属性为所有测试方法或所有测试固定例程方法全局指定超时。
注意
无法保证超时是精确的。 测试将在指定时间过后中止,但可能需要更长的时间才能取消该步骤。
使用超时功能时,将创建一个单独的线程/任务来运行测试方法。 主线程/任务负责监视超时,如果达到超时,则取消观察方法线程/任务。
从 MSTest 3.6 开始,可以在属性上指定 CooperativeCancellation 属性(或通过 runsettings 文件全局指定)以启用协作取消。 在此模式下,该方法将负责检查取消令牌,并在收到信号时中止测试,就像在典型的 async
方法中所做的那样。 此模式的性能更佳,并让你可以对取消过程进行更精确的控制。 此模式可应用于异步方法和同步方法。
STATestClassAttribute
应用于测试类时,STATestClass 属性指示类中的所有测试方法(以及类中的 [ClassInitialize]
和 [ClassCleanup]
方法)都应在单线程单元(STA)中运行。 当测试方法与需要 STA 的 COM 对象交互时,此属性非常有用。
注意
这仅在 Windows 以及版本 3.6 及更高版本中受支持。
STATestMethodAttribute
应用于测试方法时,STATestMethod 属性指示测试方法应在单线程单元(STA)中运行。 当测试方法与需要 STA 的 COM 对象交互时,此属性非常有用。
注意
这仅在 Windows 以及版本 3.6 及更高版本中受支持。
ParallelizeAttribute
默认情况下,MSTest 按顺序运行测试。 程序集级别属性 Parallelize 属性可用于并行运行测试。 可以指定并行度应处于类级别(多个类可以并行运行,但给定类中的测试将按顺序运行)还是方法级别。
还可以指定用于并行执行的最大线程数。 值 0
(默认值)表示线程数等于计算机上的逻辑处理器数。
还可以通过 runsettings 文件的 parallelization 属性指定并行度。
DoNotParallelizeAttribute
DoNotParallelize 属性可用于防止在给定的程序集中并行执行测试。 此属性可以在程序集级别、类级别或方法级别应用。
注意
默认情况下,MSTest 按顺序运行测试,因此,如果应用程序集级别 并行化 属性,则只需使用此属性。
RetryAttribute
MSTest 3.8 中引入了 Retry
属性。 此属性会导致测试方法在失败或超时时重试。 它允许你指定最大重试次数、重试之间的时间延迟以及延迟退避类型(常量或指数)。
在测试方法中预期只存在一个 RetryAttribute
,并且不能在未标记为 RetryAttribute
的方法上使用 。
注意
RetryAttribute
派生自抽象 RetryBaseAttribute
。 如果内置 RetryAttribute
不适合你的需求,还可以创建自己的重试实现。
实用工具属性
DeploymentItemAttribute
DeploymentItem 属性用于将指定为部署项的文件或文件夹复制到部署目录(无需添加自定义输出路径,复制的文件将位于项目文件夹内的 TestResults
文件夹中)。 部署目录是所有部署项以及测试项目 DLL 所在的位置。
它既可以用于标记为 TestClass 属性的测试类,也可以用于标记为 TestMethod 属性的测试方法。
用户可以使用多个属性实例来指定多个项。
可在此处查看其构造函数。
示例
[TestClass]
[DeploymentItem(@"C:\classLevelDepItem.xml")] // Copy file using some absolute path
public class UnitTest1
{
[TestMethod]
[DeploymentItem(@"..\..\methodLevelDepItem1.xml")] // Copy file using a relative path from the dll output ___location
[DeploymentItem(@"C:\DataFiles\methodLevelDepItem2.xml", "SampleDataFiles")] // File will be added under a SampleDataFiles in the deployment directory
public void TestMethod1()
{
string textFromFile = File.ReadAllText("classLevelDepItem.xml");
}
}
警告
不建议使用此属性将文件复制到部署目录。
ExpectedExceptionAttribute
ExpectedException 属性定义测试方法应引发的异常。 如果引发预期的异常并且异常消息与预期消息匹配,则测试通过。
警告
保留此属性是为了后向兼容,不建议用于新测试。 请改用 Assert.ThrowsException
方法(如果使用 MSTest 3.8 及更高版本,请改用 Assert.ThrowsExactly
)。
元数据特性
以下属性和分配给它们的值会出现在特定测试方法的 Visual Studio
“属性”窗口中。 不应通过测试代码访问这些属性。 相反,它们会影响使用或运行测试的方式(由你通过 Visual Studio IDE 使用或运行,或由 Visual Studio 测试引擎使用或运行)。 例如,其中一些属性在测试管理器 窗口和测试结果窗口中显示为列,这意味着可以使用它们对测试和测试结果进行分组和排序。
TestPropertyAttribute 就是这样的一个属性,它用于将任意元数据添加到测试。
例如,可以通过使用 [TestProperty("Feature", "Accessibility")]
标记测试,来使用该属性存储此测试所涵盖的“测试轮次”的名称。 还可以使用它存储其所属的测试类型的指示器:[TestProperty("ProductMilestone", "42")]
。 使用此特性创建的属性以及分配的属性值都会显示在 Visual Studio属性窗口中的标题测试特定的下。
- DescriptionAttribute
- IgnoreAttribute
- OwnerAttribute
- PriorityAttribute
- TestCategoryAttribute
- TestPropertyAttribute
- WorkItemAttribute
以下属性将它们修饰的测试方法与 Team Foundation Server
团队项目的项目层次结构中的实体相关联: