MSTest 属性

MSTest 使用自定义属性来标识和自定义测试。

为了帮助提供更清晰的测试框架概述,本部分将 Microsoft.VisualStudio.TestTools.UnitTesting 命名空间的成员组织为相关功能组。

注意

名称以“Attribute”结尾的属性在使用时可以添加或不添加该“Attribute”后缀。 包含无参数构造函数的属性在写入时可以添加或不添加括号。 以下代码示例的工作方式相同:

[TestClass()]

[TestClassAttribute()]

[TestClass]

[TestClassAttribute]

用于标识测试类和方法的属性

每个测试类都必须具有 TestClass 属性,每个测试方法都必须具有 TestMethod 属性。

TestClassAttribute

TestClass 属性用于标记类,该类包含测试和可选的初始化或清理方法。

可以扩展此属性来改变或扩展默认行为。

示例:

[TestClass]
public class MyTestClass
{
}

TestMethodAttribute

TestMethod 属性在 TestClass 内用于定义要运行的实际测试方法。

该方法应该是定义为 publicvoidTask 的实例 ValueTask 方法(从 MSTest v3.3 开始)。 它可以是 async,但不能是 async void

该方法应该不带参数,除非它与 [DataRow][DynamicData] 或向测试方法提供测试用例数据的类似属性一起使用。

考虑以下示例测试类:

[TestClass]
public class MyTestClass
{
    [TestMethod]
    public void TestMethod()
    {
    }
}

用于数据驱动的测试的属性

使用以下元素设置数据驱动的测试。 有关详细信息,请参阅创建数据驱动的单元测试使用配置文件定义数据源

DataRowAttribute

DataRowAttribute 允许使用多个不同的输入运行同一测试方法。 它可以在测试方法上出现一次或多次。 它应与 TestMethodAttribute 结合使用。

参数的数量和类型必须与测试方法签名完全匹配。 请考虑以下有效测试类的示例,该示例演示了 DataRow 属性的用法,以及与测试方法参数一致的内联参数:

[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 功能捕获 DataRow 的多个输入。

[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) {}
}

还可以通过继承 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 Taskstatic ValueTaskTestClass(从 MSTest v3.3 开始),并且只能出现一次。 初始化部分需要一个类型为 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)
    {
    }
}
[TestClass]
public class MyOtherTestClass
{
    [AssemblyInitialize]
    public static async Task AssemblyInitialize(TestContext testContext)
    {
    }

    [AssemblyCleanup]
    public static async Task AssemblyCleanup() // Starting with MSTest 3.8, it can be AssemblyCleanup(TestContext testContext)
    {
    }
}

类级别

ClassInitialize 在加载类之前(但在静态构造函数之后)进行调用,而 ClassCleanup 在卸载类之后进行调用。

可以控制继承行为:仅适用于使用 InheritanceBehavior.None 的当前类或使用 InheritanceBehavior.BeforeEachDerivedClass 的所有派生类。

还可以配置是在类结束时还是在程序集结束时运行类清理。

用这些属性标记的方法应在 static void 中定义为 static Taskstatic ValueTaskTestClass(从 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)
    {
    }
}
[TestClass]
public class MyOtherTestClass
{
    [ClassInitialize]
    public static async Task ClassInitialize(TestContext testContext)
    {
    }

    [ClassCleanup]
    public static async Task ClassCleanup() // Starting with MSTest 3.8, it can be ClassCleanup(TestContext testContext)
    {
    }
}

测试级别

TestInitialize 在测试开始之前进行调用,而 TestCleanup 在测试完成之后进行调用。

TestInitialize 类似于类构造函数,但通常更适合长初始化或异步初始化。 TestInitialize 始终在构造函数之后进行调用,并针对每个测试(包括数据驱动测试的每个数据行)调用一次。

TestCleanup 类似于 Dispose(或 DisposeAsync)类,但通常更适合长时间或异步清理。 TestCleanup 始终在 DisposeAsync/Dispose 之前进行调用,并针对每个测试(包括数据驱动测试的每个数据行)调用一次。

用这些属性标记的方法应在 void 中定义为 TaskValueTaskTestClass(从 MSTest v3.3 开始),不带参数,并且可以出现一次或多次。

[TestClass]
public class MyTestClass
{
    [TestInitialize]
    public void TestInitialize()
    {
    }

    [TestCleanup]
    public void TestCleanup()
    {
    }
}
[TestClass]
public class MyOtherTestClass
{
    [TestInitialize]
    public async Task TestInitialize()
    {
    }

    [TestCleanup]
    public async Task 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 按顺序运行测试,因此,仅当你在程序集级别应用了 [Parallelize] 属性时,才需要使用此属性。

实用工具属性

DeploymentItemAttribute

MSTest 框架引入了 DeploymentItemAttribute,用于将指定为部署项的文件或文件夹复制到部署目录(无需添加所复制文件在项目文件夹内的 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

MSTest 框架引入了 ExpectedExceptionAttribute,用于标记测试方法以指示预期会发生特定类型的异常。 如果引发了预期的异常并且异常消息与预期消息匹配,则测试将会通过。

警告

保留此属性是为了后向兼容,不建议用于新测试。 请改用 Assert.ThrowsException 方法(如果使用 MSTest 3.8 及更高版本,请改用 Assert.ThrowsExactly)。

元数据特性

以下属性和分配给它们的值会出现在特定测试方法的 Visual Studio“属性”窗口中。 不应通过测试代码访问这些属性。 相反,它们会影响使用或运行测试的方式(由你通过 Visual Studio IDE 使用或运行,或由 Visual Studio 测试引擎使用或运行)。 例如,其中一些属性在测试管理器 窗口和测试结果窗口中显示为列,这意味着可以使用它们对测试和测试结果进行分组和排序。 TestPropertyAttribute 就是这样的一个属性,它用于将任意元数据添加到测试。

例如,可以通过使用 [TestProperty("Feature", "Accessibility")] 标记测试,来使用该属性存储此测试所涵盖的“测试轮次”的名称。 还可以使用它存储其所属的测试类型的指示器:[TestProperty("ProductMilestone", "42")]。 使用此特性创建的属性以及分配的属性值都会显示在 Visual Studio属性窗口中的标题测试特定的下。

以下属性将它们修饰的测试方法与 Team Foundation Server 团队项目的项目层次结构中的实体相关联: