MSTest测试需显式标注[TestClass]和[TestMethod],类与方法均须public、无参、返回void/Task;断言必须用Assert类;避免TestInitialize重操作;命名应描述行为;注意测试隔离性。

测试类和方法必须加特性才能被识别
MSTest 不会自动把普通类或方法当测试用,必须显式标注。缺了 [TestClass] 或 [TestMethod],测试资源管理器里就看不到它,dotnet test 也执行不到。
常见错误是:类加了 [TestClass],但方法忘了 [TestMethod];或者方法写了 [TestMethod],但类没加 [TestClass];还有人写成 [Test](那是 NUnit 的写法)。
- 测试类必须是
public,不能是internal或private - 测试方法必须是
public、无参数、返回void或Task -
[TestInitialize]和[TestCleanup]方法也必须是public、无参、void - 别误用
[ClassInitialize]——它要求方法是static,且整个测试类只运行一次,容易造成状态污染
断言要用 Assert 类,别手写 if + throw
写 if (result != expected) throw new Exception(...) 看似能报错,但测试框架无法捕获、归类、统计,还会让测试资源管理器显示为“未执行”或“异常终止”,而不是“失败”。
所有判断都得走 Assert 静态类,比如 Assert.AreEqual()、Assert.IsTrue()、Assert.Throws<ArgumentException>(() => ...)。
- 异步方法断言要用
await Assert.ThrowsAsync<TException>(...),不是Assert.Throws - 比较浮点数别用
AreEqual,改用AreApproximatelyEqual并指定容差 - 验证集合内容别只比长度,用
CollectionAssert.AreEqual或IsSubsetOf等专用方法
避免在 TestInitialize 里做重操作
[TestInitialize] 方法会在每个测试方法前执行一次,如果里面连数据库、读大文件、启 HTTP 服务,测试整体耗时会指数级上升,CI 流水线可能超时。
工控或嵌入式场景下还容易触发硬件资源抢占,比如两个测试同时初始化同一个串口模拟器。
- 只放轻量初始化:new 对象、mock 设置、内存字典填充
- 数据库连接等共享资源建议用单例 + 懒加载,或提取到
[AssemblyInitialize](注意线程安全) - 真要测 IO,优先用内存替代:比如用
InMemoryDatabase替代 SQL Server,用HttpClientHandler拦截响应 - 实时性敏感测试(如 PLC 响应),加上
[TestMethod, Timeout(50)]明确约束执行窗口
测试命名必须表达行为,不是函数名
叫 TestAdd 或 AddTest 对 CI 没影响,但对人是灾难。当一个测试失败,你得花 2 分钟翻代码才知道它到底在验什么边界条件。
命名规则本质是“自然语言描述预期行为”,MSTest 自己不解析名字,但团队协作和排查成本全靠它。
- 推荐格式:
Add_TwoNegativeNumbers_ReturnsNegativeSum - 包含输入条件(
TwoNegativeNumbers)、动作(Add)、输出结果(ReturnsNegativeSum) - 避免模糊词:不要用
Valid、Normal、ShouldWork,换成具体值或状态,比如WhenDivisorIsZero_ThrowsDivideByZeroException - 数据驱动测试用
[DataTestMethod]+[DataRow]时,每个 case 仍需独立命名逻辑,别指望靠参数值说明问题
[TestInitialize],如果 mock 对象、静态字段、配置单例没重置干净,一个测试的副作用就可能让另一个测试偶然通过或失败。这种非确定性问题,在工控或金融类强一致性场景中尤其危险。


















