使用 Assert 命名空间的 Microsoft.VisualStudio.TestTools.UnitTesting 类来验证特定功能。 测试方法运行应用程序中的代码,但只有在包含 Assert 语句时才报告正确性。
概述
MSTest 提供三个断言类:
| Class | 目的 |
|---|---|
Assert |
通用的值、类型和异常断言。 |
StringAssert |
针对字符串的模式、子字符串和比较的断言。 |
CollectionAssert |
用于比较和验证集合的集合断言。 |
重要
对于新代码,请始终使用该 Assert 类。
StringAssert 和 CollectionAssert 类可能会在未来的某个版本中被弃用。 它们主要用于向后兼容,但不建议这样做,因为跨三种类型拆分断言会损害可发现性。
所有断言方法都接受一个可选消息参数,该参数在断言失败时显示,有助于确定原因:
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
- Assert.AreEqual
- Assert.AreNotEqual
- Assert.AreNotSame
- Assert.AreSame
- Assert.Contains
- Assert.ContainsSingle
- Assert.DoesNotContain
- Assert.DoesNotEndWith
- Assert.DoesNotMatchRegex
- Assert.DoesNotStartWith
- Assert.Fail
- Assert.HasCount
- Assert.Inconclusive
- Assert.IsEmpty
- Assert.IsFalse
- Assert.IsGreaterThan
- Assert.IsGreaterThanOrEqualTo
- Assert.IsInRange
- Assert.IsInstanceOfType
- Assert.IsLessThan
- Assert.IsLessThanOrEqualTo
- Assert.IsNegative
- Assert.IsNotEmpty
- Assert.IsNotInstanceOfType
- Assert.IsNotNull
- Assert.IsNull
- Assert.IsPositive
- Assert.IsTrue
- Assert.MatchesRegex
- Assert.StartsWith
- Assert.Throws
- Assert.ThrowsAsync
- Assert.ThrowsExactly
- Assert.ThrowsExactlyAsync
StringAssert 类
使用 StringAssert 类来比较和检查字符串。
警告
StringAssert 类可能会在未来的版本中被弃用。 它仅用于向后兼容性,不建议用于新代码。 所有 StringAssert 方法对 Assert 类具有等效项,可提供更好的可发现性。 若要迁移现有使用情况,请参阅分析器 MSTEST0046。
可用的 API 包括:
- StringAssert.Contains
- StringAssert.DoesNotMatch
- StringAssert.EndsWith
- StringAssert.Matches
- StringAssert.StartsWith
CollectionAssert 类
使用 CollectionAssert 类比较对象的集合,并验证集合的状态。
警告
CollectionAssert 类可能会在未来的版本中被弃用。 它主要用于向后兼容性,不建议用于新代码。 如果 Assert 上存在等效方法(例如 Assert.Contains、Assert.DoesNotContain 或 Assert.HasCount),请使用 Assert,以提高可发现性。
可用的 API 包括:
- CollectionAssert.AllItemsAreInstancesOfType
- CollectionAssert.AllItemsAreNotNull
- CollectionAssert.AllItemsAreUnique
- CollectionAssert.AreEqual
- CollectionAssert.AreEquivalent
- CollectionAssert.AreNotEqual
- CollectionAssert.AreNotEquivalent
- CollectionAssert.Contains
- CollectionAssert.DoesNotContain
- CollectionAssert.IsNotSubsetOf
- CollectionAssert.IsSubsetOf
使用 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);
}
StringAssert 和 CollectionAssert 上的扩展钩子
StringAssert.That 和 CollectionAssert.That 属性为了向后兼容,提供了相同的单例模式。 对于新的自定义断言,始终以 Assert.That 为目标。 否则,这些辅助程序将继承与旧类相同的可发现性问题,而且如果 StringAssert 和 CollectionAssert 被弃用,它们也需要迁移。
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类。StringAssert和CollectionAssert类可能会在未来的版本中被弃用。为自定义断言扩展
Assert.That:为了确保一致的可发现性,请将自定义断言添加为Assert上的扩展方法,并通过Assert.That调用它们。 不要在新代码中以StringAssert.That或CollectionAssert.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.ThrowsMSTEST0051应包含单个语句。 -
MSTEST0053 - 避免
Assert格式参数。 - MSTEST0058 - 避免在 catch 块中断言。