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

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










