MSTest 断言

使用 Assert 命名空间的 Microsoft.VisualStudio.TestTools.UnitTesting 类来验证特定功能。 测试方法运行应用程序中的代码,但只有在包含 Assert 语句时才报告正确性。

概述

MSTest 提供三个断言类:

Class 目的
Assert 通用的值、类型和异常断言。
StringAssert 针对字符串的模式、子字符串和比较的断言。
CollectionAssert 用于比较和验证集合的集合断言。

重要

对于新代码,请始终使用该 Assert 类。 StringAssertCollectionAssert 类可能会在未来的某个版本中被弃用。 它们主要用于向后兼容,但不建议这样做,因为跨三种类型拆分断言会损害可发现性。

所有断言方法都接受一个可选消息参数,该参数在断言失败时显示,有助于确定原因:

Assert.AreEqual(expected, actual, "Values should match after processing");

Assert

使用 Assert 类验证所测试的代码是否按预期方式运行。

常见断言方法

[TestMethod]
public async Task AssertExamples()
{
    // Equality
    Assert.AreEqual(5, calculator.Add(2, 3));
    Assert.AreNotEqual(0, result);

    // Reference equality
    Assert.AreSame(expected, actual);
    Assert.AreNotSame(obj1, obj2);

    // Boolean conditions
    Assert.IsTrue(result > 0);
    Assert.IsFalse(string.IsNullOrEmpty(name));

    // Null checks
    Assert.IsNull(optionalValue);
    Assert.IsNotNull(requiredValue);

    // Type checks
    Assert.IsInstanceOfType<IDisposable>(obj);
    Assert.IsNotInstanceOfType<string>(obj);

    // Exception testing (MSTest v3.8+)
    Assert.ThrowsExactly<ArgumentNullException>(() => service.Process(null!));
    await Assert.ThrowsExactlyAsync<InvalidOperationException>(
        async () => await service.ProcessAsync());
}

可用 API

StringAssert

使用 StringAssert 类来比较和检查字符串。

警告

StringAssert 类可能会在未来的版本中被弃用。 它仅用于向后兼容性,不建议用于新代码。 所有 StringAssert 方法对 Assert 类具有等效项,可提供更好的可发现性。 若要迁移现有使用情况,请参阅分析器 MSTEST0046

可用的 API 包括:

CollectionAssert

使用 CollectionAssert 类比较对象的集合,并验证集合的状态。

警告

CollectionAssert 类可能会在未来的版本中被弃用。 它主要用于向后兼容性,不建议用于新代码。 如果 Assert 上存在等效方法(例如 Assert.ContainsAssert.DoesNotContainAssert.HasCount),请使用 Assert,以提高可发现性。

可用的 API 包括:

使用 Assert.That 创建自定义断言

内置断言方法并不涵盖每个方案。 若要使用你自己的检查来扩展断言基础结构,MSTest 将 Assert.That 这一单例属性作为扩展点公开。 你可以在 Assert 实例类型上将自定义断言添加为 C# 扩展方法,调用方则使用熟悉的 Assert.That.MyAssertion(...) 语法来调用这些断言。

为了提高可发现性,在专用静态类中组织项目范围的断言。 通过 Assert.That 访问的自定义断言与 IntelliSense 中的内置方法一起显示,因此使用者不必记住单独的帮助程序类型。

创作自定义断言

添加一个以 Assert 类型为目标的扩展方法,并在条件失败时抛出 AssertFailedException

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

public static class CustomAssertExtensions
{
    public static void IsPrime(this Assert assert, int value)
    {
        if (value < 2 || Enumerable.Range(2, (int)Math.Sqrt(value) - 1).Any(i => value % i == 0))
        {
            throw new AssertFailedException($"Assert.That.IsPrime failed. Value <{value}> is not a prime number.");
        }
    }
}

使用自定义断言

导入包含扩展方法的命名空间后,请通过以下方法 Assert.That调用自定义断言:

[TestMethod]
public void Compute_ReturnsPrime()
{
    int result = _calculator.NextPrime(10);
    Assert.That.IsPrime(result);
}

StringAssertCollectionAssert 上的扩展钩子

StringAssert.ThatCollectionAssert.That 属性为了向后兼容,提供了相同的单例模式。 对于新的自定义断言,始终以 Assert.That 为目标。 否则,这些辅助程序将继承与旧类相同的可发现性问题,而且如果 StringAssertCollectionAssert 被弃用,它们也需要迁移。

Assert.That 属性与 Assert.That(...) 方法

注释

不要将 Assert.That单例属性(用作扩展点)与 MSTest 3.8 中新增的 Assert.That(() => condition)方法混淆。 后者接受布尔表达式,并通过分析表达式树(例如, Assert.That(() => order.Total > 0))生成详细的失败消息。 这两个 API 共享一个名称,但用途不同。

最佳做法

  • 使用特定断言:优先使用 AreEqual 而不是 IsTrue(a == b),以获得更好的故障消息。

  • 包括描述性消息:帮助使用明确的断言消息快速识别故障。

  • 一次测试一件事:每个测试方法都应验证单个行为。

  • 使用 Throws/ThrowsExactly来处理异常:在 MSTest v3.8+ 中,优先使用Assert.ThrowsAssert.ThrowsExactly及其异步对应的 ThrowsAsyncThrowsExactlyAsync,而不是 ExpectedException 属性。

  • 优先使用 Assert,而不是 StringAssert/CollectionAssert:为了提高可发现性和一致性,请使用 Assert 类。 StringAssertCollectionAssert 类可能会在未来的版本中被弃用。

  • 为自定义断言扩展 Assert.That:为了确保一致的可发现性,请将自定义断言添加为 Assert 上的扩展方法,并通过 Assert.That 调用它们。 不要在新代码中以 StringAssert.ThatCollectionAssert.That 为目标。

以下分析器有助于确保正确使用断言:

  • MSTEST0006 - 避免 ExpectedException 属性,改用 Assert.Throws 方法。
  • MSTEST0017 - 断言参数应按正确的顺序传递。
  • MSTEST0023 - 不要否定布尔断言。
  • MSTEST0025 - 优先使用 Assert.Fail 而不是总是为假条件。
  • MSTEST0026 - 断言参数应避免条件访问。
  • MSTEST0032 - 查看总为真的断言条件。
  • MSTEST0037 - 使用正确的断言方法。
  • MSTEST0038 - 避免 Assert.AreSame 与值类型一起使用。
  • MSTEST0039 - 使用较 Assert.Throws 新的方法。
  • MSTEST0040 - 避免在异步 void 上下文中使用断言。
  • MSTEST0046 - 使用 Assert 而不是 StringAssert
  • - Assert.Throws MSTEST0051应包含单个语句。
  • MSTEST0053 - 避免 Assert 格式参数。
  • MSTEST0058 - 避免在 catch 块中断言。

另请参阅