Assert.AreEqual对引用类型默认比较引用地址而非内容,因多数类未重写Equals;值类型安全;引用类型应优先用Assert.IsTrue(obj1.Equals(obj2))并确保重写Equals和GetHashCode。

为什么 Assert.AreEqual 有时不报错但逻辑不对
因为 Assert.AreEqual 对引用类型默认调用 Equals,而多数自定义类没重写它,导致比较的是引用地址而非内容。比如两个新构造的 Person 对象字段完全一样,AreEqual 仍返回 false。
- 值类型(
int、DateTime、struct)安全,直接用 - 引用类型优先用
Assert.IsTrue(obj1.Equals(obj2)),并确保已重写Equals和GetHashCode - 快速验证对象结构一致?改用
Newtonsoft.Json.JsonConvert.SerializeObject序列化后比字符串(仅限无循环引用、无动态字段的场景) - 集合比较别用
AreEqual—— 改用CollectionAssert.AreEqual(顺序敏感)或CollectionAssert.AreEquivalent(忽略顺序)
如何让 [TestMethod] 正确识别异步方法
直接写 async void TestMethod() 会导致测试框架无法等待完成,常表现为“测试通过”但实际没执行完断言,或抛出 InvalidCastException(因 MSTest v2 不支持 async void)。
- 必须返回
Task:声明为public async Task MyTest() - 不要在测试里用
.Wait()或.Result—— 可能引发死锁(尤其在 UI 或 ASP.NET 同步上下文里) - 需要测试异常?用
await Assert.ThrowsExceptionAsync<myexception>(async () => await target.Method())</myexception> - MSTest、xUnit、NUnit 都支持
Task返回值,但 xUnit 要求方法名不能含Async后缀(命名随意),而 MSTest 无此限制
[DataRow] 和 [DynamicData] 怎么选才不掉坑
[DataRow] 写死参数,编译期确定;[DynamicData] 运行时生成数据,灵活但易出错。
-
[DataRow]适合小规模、稳定输入(如边界值:0,-1,int.MaxValue);参数类型必须和方法签名严格匹配,否则编译失败 -
[DynamicData]方法必须是static,返回IEnumerable<object></object>;若返回 null 或 yield break,测试会跳过(不报错!容易漏测) - 路径读取 JSON/CSV 做动态数据?确保测试运行目录正确 —— 默认工作目录是
bin\Debug\net6.0\,不是项目根目录,建议用Path.Combine(AppContext.BaseDirectory, "data.json") - 避免在
[DynamicData]方法里做耗时操作(如 HTTP 请求),它会在发现测试阶段就被调用,拖慢测试发现速度
为什么 Moq 的 Setup 没生效
常见原因是被 mock 的方法不是 virtual、interface 成员,或调用了未 setup 的重载。
- 类中要 mock 的方法必须是
virtual(或protected virtual),且不能是static、sealed、private - 接口方法天然可 mock,但注意:
Func<t></t>属性(如IMyService Factory { get; })需 setup getter,不是直接 new Mock - 用
It.IsAny<string>()</string>匹配参数时,所有参数都得用It.IsAny或具体值 —— 混用(如一个用"test",另一个用It.IsAny<int>()</int>)会导致 setup 不命中 - 验证是否调用:用
mock.Verify(x => x.Save(It.IsAny<user>()), Times.Once)</user>,而不是mock.VerifyAll()(已过时,且行为不可控)
测试里最麻烦的从来不是写断言,而是搞清“到底哪个环节没按预期走”——比如异步没等完、mock 方法根本没被调用、或者数据源路径在 CI 环境里压根不存在。这些地方不打日志、不单步进,光看绿色对勾只会让你更困惑。










