dotnet test 能运行不代表测试正确:需确保项目引用有效、框架版本一致、internal 成员可见性配置正确;合理选用 assert.areequal 与 assert.istrue;区分不同框架的参数化测试特性;重视 setup/teardown 资源隔离与释放;覆盖边界值、空输入及异常路径。

dotnet test 能跑起来,不代表测试写对了——很多初学者的 Assert 没验证关键行为,或者根本没覆盖边界条件。
怎么让测试项目真正引用被测项目
这是最常卡住的第一步。VS 里右键测试项目 → “添加项目引用” 只是表面操作,实际要确认两点:
-
.csproj文件里是否真有<projectreference include="..\YourApp\YourApp.csproj"></projectreference> - 被测项目的
TargetFramework(如net8.0)和测试项目是否一致,不一致会编译通过但运行时报System.IO.FileNotFoundException - 如果被测类是
internal,需在被测项目的AssemblyInfo.cs或.csproj中加:<internalsvisibleto>YourTestProjectName</internalsvisibleto>
Assert.AreEqual 和 Assert.True 别混用
它们语义完全不同,错用会导致误判通过:
-
Assert.AreEqual(5, result):检查值相等,支持重载、浮点容差、自定义比较器 -
Assert.IsTrue(result == 5):只判断布尔表达式,一旦result是null或类型不匹配,直接抛NullReferenceException,而不是清晰的断言失败 - 对返回
bool的方法(如IsPrime),用Assert.IsTrue(_checker.IsPrime(2))更直白;但别写成Assert.AreEqual(true, _checker.IsPrime(2))——冗余且掩盖意图
DataRow 和 TestCase 不是等价替换
你可能想快速跑多组输入,但 MSTest 的 [DataRow] 和 NUnit 的 [TestCase] 行为差异明显:
-
[DataRow(1, 2, 3)](MSTest):参数顺序必须与测试方法签名严格一致,且不支持命名参数 -
[TestCase(1, 2, Expected = 3)](NUnit):可指定Expected、TestName等元数据,失败时日志更清晰 - xUnit 的
[Theory] + [InlineData]不支持Expected属性,得靠方法体内Assert.Equal(expected, actual)显式比对 - 所有框架中,若某组
DataRow或TestCase失败,只会报告该组失败,不影响其他组执行
Setup/Teardown 容易忽略生命周期陷阱
[SetUp](NUnit)、[TestInitialize](MSTest)不是“每次测试前 new 一次对象”就完事:
- 它们在每个测试方法前执行,但对象实例不会自动销毁 —— 如果你在
SetUp中 new 了一个共享状态的类(比如含静态字段或单例依赖),多个测试会互相污染 - 数据库连接、文件句柄、
HttpClient实例这类资源,不能只靠SetUp创建,还必须在TearDown或Dispose中显式释放,否则dotnet test连续运行时可能报SocketException或文件占用 - MSTest 的
[ClassInitialize]是静态方法,只能访问静态字段;NUnit 的[OneTimeSetUp]同理,别在里面初始化实例成员
[TestMethod],而是让每个测试彼此隔离、失败时能一眼看出哪条路径崩了、并且不因环境或顺序变化而偶然通过。边界值、空输入、异常路径——这些地方漏掉一个 Assert.Throws<argumentexception>(() => target.Method(null))</argumentexception>,上线后就可能变成生产事故。










