如何让SpecFlow.NUnit在控制台输出中屏蔽通过的场景?
问题描述
用dotnet test跑SpecFlow测试套件时,只想看失败场景的步骤输出——毕竟有近200个场景,不想被通过的内容刷屏。之前项目升级所有测试NuGet包前,正常逻辑是:全部通过只显示总结行,有失败时才展示失败测试的步骤,现在升级后这个行为没了,得找办法恢复。
当前用的NuGet包:
<ItemGroup> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" /> <PackageReference Include="NUnit" Version="4.1.0" /> <PackageReference Include="NUnit.ConsoleRunner" Version="3.17.0" /> <PackageReference Include="NUnit3TestAdapter" Version="4.5.0" /> <PackageReference Include="SpecFlow" Version="3.9.74" /> <PackageReference Include="SpecFlow.NUnit" Version="3.9.74" /> <PackageReference Include="SpecFlow.Tools.MsBuild.Generation" Version="3.9.74" /> </ItemGroup>
关键情况:就算把SpecFlow降级到旧版本3.3.57,问题还是存在,看来是NUnit升级导致的输出变化。
已经试过但没用的方法:
dotnet test的verbosity参数:--l "console;verbosity=quiet"会把失败输出也藏了,minimal又会显示一堆通过场景的内容- 修改
specflow.json加"traceSuccessfulSteps": false,完全没效果 - 建
.runsettings配置NUnit的InternalTraceLevel和Verbosity,输出一点没变
可行解决方案
1. 调整NUnit3TestAdapter的日志级别
NUnit3TestAdapter 4.x的日志逻辑改了,给.runsettings加LogLevel配置就能过滤输出:
<?xml version="1.0" encoding="utf-8"?> <RunSettings> <NUnit> <LogLevel>Warning</LogLevel> </NUnit> </RunSettings>
跑测试的时候指定这个配置文件:
dotnet test --filter TestCategory!=wip koala.IntegrationTests/ --settings .runsettings
2. 换用NUnit Console Runner
既然已经装了NUnit.ConsoleRunner,直接用它跑测试,能更精准控制输出:
dotnet nunit koala.IntegrationTests/bin/Debug/net[你的框架版本]/koala.IntegrationTests.dll --where "cat != wip" --labels=Off --trace=Error
--labels=Off:关掉测试名称的重复输出--trace=Error:只输出错误级别的日志,自动过滤通过场景的步骤
3. 回退NUnit到兼容版本
如果上面的方法都不行,可以试试把NUnit回退到3.x的稳定版(比如3.13.3),同时把NUnit3TestAdapter也回退到对应的兼容版本(比如3.17.0),匹配之前正常工作的版本组合。
4. 自定义SpecFlow输出拦截
通过SpecFlow的ITraceListener接口自己写逻辑,只在测试失败时打印步骤:
- 写个自定义的TraceListener类:
using TechTalk.SpecFlow.Tracing; using TechTalk.SpecFlow.Infrastructure; namespace YourNamespace { public class FailOnlyTraceListener : ITraceListener { private readonly ITraceListener _innerListener; private bool _shouldLog; public FailOnlyTraceListener(ITraceListener innerListener) { _innerListener = innerListener; } public void WriteTestOutput(string message) { if (_shouldLog) _innerListener.WriteTestOutput(message); } public void WriteToolOutput(string message) { _innerListener.WriteToolOutput(message); } public void TestFinished(TestResult testResult) { _shouldLog = testResult.Status != TestStatus.Passed; if (_shouldLog) _innerListener.TestFinished(testResult); } public void TestStarted(string testName) => _innerListener.TestStarted(testName); public void StepStarted(StepInfo stepInfo) => _innerListener.StepStarted(stepInfo); public void StepFinished(StepInfo stepInfo, TestResult result) { if (_shouldLog) _innerListener.StepFinished(stepInfo, result); } public void ScenarioStarted(ScenarioInfo scenarioInfo) => _innerListener.ScenarioStarted(scenarioInfo); public void ScenarioFinished(ScenarioInfo scenarioInfo, TestResult result) { _shouldLog = result.Status != TestStatus.Passed; if (_shouldLog) _innerListener.ScenarioFinished(scenarioInfo, result); } public void FeatureStarted(FeatureInfo featureInfo) => _innerListener.FeatureStarted(featureInfo); public void FeatureFinished(FeatureInfo featureInfo) => _innerListener.FeatureFinished(featureInfo); } }
- 在
specflow.json里注册这个监听器:
{ "listeners": [ { "type": "YourNamespace.FailOnlyTraceListener, YourAssemblyName" } ] }
内容的提问来源于stack exchange,提问作者Grant Birchmeier
相关产品推荐
相关产品推荐

