这是一个真实的坑:
dotnet test匹配到 0 个测试,却以退出码 0、全绿收场。
一、引子:我以为跑了 12 个测试,结果跑了 0 个
某天我在测试项目里加了一个新用例文件,然后跑:
dotnet test --filter "FullyQualifiedName~NativeDriverIntegrationTests"
输出很快,全绿,退出码 0。我以为 12 个集成测试都过了。
直到我打开 TRX 报告想看一眼结果明细,发现汇总里写着:
<Counters total="0" executed="0" passed="0" failed="0" />
一个测试都没执行。 而 dotnet test 的退出码是 0——命令成功了。
二、根因:文件名 ≠ 类名
问题出在我用文件名写 filter,而那个文件里的类名根本不是它:
文件:Drivers/NativeDriverIntegrationTests.cs
类: SiemensS7Integration / ModbusTcpIntegration / MitsubishiMcIntegration ...
↑ 没有任何一个类叫 NativeDriverIntegrationTests
--filter "FullyQualifiedName~NativeDriverIntegrationTests" 匹配不到任何测试 → 0 个执行 → 退出码 0。
这不是我一个人的问题:同一个仓库里还有 RealS7HundredPlcStressTests.cs(类名其实是 RealS7StressTests)——文件名和类名不一致在项目里不止一处,尤其当文件是"多类合放"或"历史命名迁移"时很常见。
三、为什么它比"测试失败"更危险
失败是显性的——红了你会去查。静默空跑是隐性的:
- CI 全绿、覆盖率为零、你还以为"测过了";
- 它在每个你不知道的时候发生:filter 写错、类被改名、文件被合并——都是静默的;
- 和"跳过记通过"是同一个家族的病:"没测到"和"通过"在外观上没有区别。
四、三个防坑动作(一条命令 + 一条习惯 + 一条脚本校验)
1. 跑之前,先 --list-tests 看真实类名
dotnet test --filter "FullyQualifiedName~NativeDriverIntegration" --list-tests
# 输出为空 → filter 必错;输出列出 FQN → 用列出来的名字过滤
用类名(而不是文件名)写 filter:
dotnet test --filter "FullyQualifiedName~SiemensS7Integration"
2. 习惯:filter 里带上"必匹配"的锚
如果目标是"这个类",写成 FullyQualifiedName~SiemensS7Integration 而不是可能空匹配的名字;避免用"太短/太常见"的子串(~Integration 可能匹配 5 个类,~NativeDriverIntegrationTests 匹配 0 个,都不符合直觉)。
3. 脚本里校验"真的跑了"
在自动化脚本/CI 步骤里,别只信退出码:
# 解析 TRX 或 --logger 输出,断言 executed > 0,否则以非 0 退出
grep -q 'executed="[1-9]' result.trx || {
echo "0 个测试被执行,视为失败"; exit 1; }
这一步是"防假绿":"没测到"必须显式失败,而不是静默通过(我们给压测套件配的防假绿哨兵,就是这个思路的通用版)。
五、收尾一句
测试框架的"退出码 0"只表示"命令没出错",不表示"测了什么"。 凡是"全绿但覆盖为零"的场景,都值得怀疑——尤其是 filter、条件编译、Skip 这三类最容易静默的地方。
我们做工业数据采集(PLC 批量采集引擎)。这篇文章来自我们测试体系的真实排障(同一个坑在仓库里出现不止一次);免费版 10 台、协议全开、可读可写、完整编排。
获取与授权:
ZL.IotHub—— 工业 PLC 数据采集运行时,22 种自研原生驱动
(西门子 S7 / 三菱 MC / 欧姆龙 FINS / AB / 倍福 ADS / Modbus 全系 / 台达 / 汇川 / 信捷 /
埃斯顿 / 基恩士 / 松下 / DALI / DLMS / M-Bus / HART-IP / MTConnect / HTTP-REST 等),
内置地址合并批量读取、坏点隔离与变化上报、DataChange 事件。
可以用于数据采集,设备控制,SCADA 等系统的底座,编程简单,运行稳定高效。免费版:≤10 台设备、协议全开、可读可写,直接用于生产验证;超过 10 台需正式设备授权。
**安装:dotnet add package ZL.IotHub
(NuGet 页面)
示例(可直接运行):https://github.com/qwdingyu/ZL.IotHubDemo