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

2次阅读

assert.areequal 比较值相等(调用 equals 或 ==),assert.aresame 比较引用相等(同一内存地址);对引用类型二者行为不同,String 因驻留可能使 aresame 偶然通过但不可依赖。

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

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

两者都用于判断两个值是否相等,但语义和行为完全不同:AreEqual 比较的是「值相等」(调用 Equals() 或重载的 ==),AreSame 比较的是「引用相等」(即是否指向同一内存地址)。

  • 值类型(如 intDateTime),AreEqualAreSame 行为一致,因为值类型没有引用共享问题
  • 对引用类型(如 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());

断言不是越写越多就越安全;关键在于选对方法、理解语义差异,尤其是引用/值比较、异常捕获时机、以及测试框架底层机制的差异。这些地方一错,测试本身就成了漏洞。

text=ZqhQzanResources