C# 断言使用方法 C#在测试中如何使用Assert

来源:这里教程网 时间:2026-02-21 17:42:06 作者:

Assert.AreEqual 和 Assert.AreSame 的区别在哪

两者都用于判断两个值是否相等,但语义和行为完全不同:

AreEqual
比较的是「值相等」(调用
Equals()
或重载的 ==),
AreSame
比较的是「引用相等」(即是否指向同一内存地址)。

对值类型(如
int
DateTime
),
AreEqual
AreSame
行为一致,因为值类型没有引用共享问题
对引用类型(如
string
、自定义类),
AreEqual("a", "a")
通常通过,但
AreSame(new string('a', 1), new string('a', 1))
一定失败
string
是特例:由于字符串驻留(interning),
AreSame("hello", "hello")
可能意外通过,但不应依赖此行为
Assert.AreEqual(5, 2 + 3); // ✅ 通过
Assert.AreSame(new List<int>(), new List<int>()); // ❌ 失败:两个不同实例
Assert.AreEqual(new List<int> {1}, new List<int> {1}); // ❌ 失败:List<T> 默认不重写 Equals

Assert.ThrowsException 怎么捕获具体异常并验证消息

它不只是检查是否抛出异常,还能返回异常对象,方便进一步断言其属性,比如

Message
或自定义字段。

必须用泛型指定期望的异常类型,否则会匹配所有派生类型(如
Assert.ThrowsException<exception></exception>
过于宽泛)
不能直接在 lambda 中写
throw new ArgumentException(...)
,必须是被测代码实际执行路径中抛出的
若被测方法是异步的,要用
Assert.ThrowsExceptionAsync<t></t>
var ex = Assert.ThrowsException<ArgumentException>(() => ParseAge("-5"));
Assert.IsTrue(ex.Message.Contains("age")); // 验证消息内容
Assert.AreEqual("age", ex.ParamName); // 验证 ParamName 字段

Assert.That 在 NUnit 中为什么比 MSTest 的 Assert 更灵活

Assert.That
是 NUnit 的核心断言入口,基于约束(Constraint)模型,天然支持链式表达和组合条件,而 MSTest 的
Assert
是静态方法集合,扩展性弱。

Assert.That(actual, Is.EqualTo(expected).Within(0.001))
可轻松加容差,MSTest 需用
AreEqual(double, double, double)
且仅限 double
Assert.That(list, Has.Count.EqualTo(3).And.All.GreaterThan(0))
一行完成多个维度校验
NUnit 支持自定义
Constraint
,MSTest 几乎无法扩展断言逻辑
MSTest v3 已引入部分类似语法(如
Assert.That
别名),但底层仍不支持约束组合

测试中 Assert.Fail() 和 try/catch + Assert 一起用会出什么问题

直接在

try
块里调用
Assert.Fail()
并不能达到“预期异常未抛出就失败”的目的——它会让测试无条件失败,掩盖了真实逻辑分支。

正确做法是把被测代码放在
try
外,用
Assert.ThrowsException
托管整个执行和异常捕获过程
手动
try/catch
后再
Assert.Fail()
属于反模式:既冗余又易漏掉
catch
之外的异常
如果真要手写控制流(极少见),必须确保
catch
块外有
Assert.Fail()
,否则异常未发生时测试会静默通过
// ❌ 错误:无论是否抛异常,Assert.Fail() 都执行
try { DoSomething(); } catch (InvalidOperationException) { }
Assert.Fail("Expected exception not thrown");
// ✅ 正确:交给框架处理
Assert.ThrowsException<InvalidOperationException>(() => DoSomething());
断言不是越写越多就越安全;关键在于选对方法、理解语义差异,尤其是引用/值比较、异常捕获时机、以及测试框架底层机制的差异。这些地方一错,测试本身就成了漏洞。

相关推荐