Skip to content

Instantly share code, notes, and snippets.

@chrisoldwood
Last active December 5, 2022 10:39
Show Gist options
  • Save chrisoldwood/fce752bab1f7060dc7b2 to your computer and use it in GitHub Desktop.
Save chrisoldwood/fce752bab1f7060dc7b2 to your computer and use it in GitHub Desktop.
Custom SpecFlow listener and "logging" class to reduce noise when running SpecFlow tests from the command line.
using TechTalk.SpecFlow;
namespace MyCompany.SpecFlowTests
{
[Binding]
public static class Hooks
{
[BeforeFeature]
public static void BeforeFeature()
{
Console.WriteLine();
Console.WriteLine("Feature: " + FeatureContext.Current.FeatureInfo.Title);
}
}
}
using System;
using System.Collections.Generic;
using TechTalk.SpecFlow;
namespace MyCompany.SpecFlowTests
{
using LogBuffer = List<string>;
[Binding]
internal static class ScenarioLog
{
public static void Write(string format, params object[] args)
{
if (ScenarioContext.Current != null)
{
var message = String.Format(format, args);
if (!ScenarioContext.Current.ContainsKey(ScenarioLogKey))
ScenarioContext.Current[ScenarioLogKey] = new LogBuffer();
var log = (LogBuffer)ScenarioContext.Current[ScenarioLogKey];
log.Add(message);
}
}
[AfterScenario]
public static void HandleScenarioFailure()
{
if (ScenarioContext.Current.TestError != null)
DumpLog();
}
private static void DumpLog()
{
if (ScenarioContext.Current.ContainsKey(ScenarioLogKey))
{
Console.WriteLine("\nScenario: {0}", ScenarioContext.Current.ScenarioInfo.Title);
var log = (LogBuffer)ScenarioContext.Current[ScenarioLogKey];
foreach (var message in log)
Console.WriteLine(message);
}
}
private const string ScenarioLogKey = "ScenarioLog";
}
}
using System;
using TechTalk.SpecFlow;
using TechTalk.SpecFlow.Tracing;
// <specFlow>
// <trace traceSuccessfulSteps="false" listener="MyCompany.SpecFlowTests.SpecFlowTestListener, MyCompany.SpecFlowTests" />
// </specFlow>
namespace MyCompany.SpecFlowTests
{
public class SpecFlowTestListener : ITraceListener
{
public AcceptanceTestListener()
{
var disableTrace = Environment.GetEnvironmentVariable(DisableTraceVariable);
if (String.IsNullOrWhiteSpace(disableTrace))
_listener = new DefaultListener();
}
public void WriteTestOutput(string message)
{
if (_listener != null)
_listener.WriteTestOutput(message);
}
public void WriteToolOutput(string message)
{
if (_listener != null)
_listener.WriteToolOutput(message);
}
private readonly ITraceListener _listener;
private const string DisableTraceVariable = "DISABLE_SPECFLOW_TRACE_OUTPUT";
}
}
@chrisoldwood
Copy link
Author

When running SpecFlow tests on the command line, or via a CI tool like Jenkins, the output can be very verbose. It's easy to configure a "null listener" to get no output at all but it's not so easy to create one that provides a nice quiet output when times are good and noisy only when things go wrong. The custom listener above does just that, you get a more minimalist output that only includes the feature name and progress dots, ala NUnit:

Feature: Use login
.....
Feature: Checkout basket
..........

Whilst the Hooks and SpecFlowTestListener classes minimise the output, the ScenarioLog class allows you to capture trace information (such as intermediate values, URLs, etc.) in a way that's invisible unless the scenario fails. At that point the lines of trace for just that scenario are dumped to the output too.

By default this listener is not active so that developers get the output they are used to. If you use a tool like ReSharper to run the tests you are probably interested in the output you normally see. Where this hook is more useful is when running the tests from the command line, such as during a pre-commit smoke build, or to reduce the noise in your CI server's logs. To activate the listener you need to set the environment variable DISABLE_SPECFLOW_TRACE_OUTPUT. For example in my local build script I'd normally include the following line to keep the output sane in my console window:

SET DISABLE_SPECFLOW_TRACE_OUTPUT=TRUE

Note: Don't forget to add the specFlow section at the top of SpecFlow.TraceListener.cs to the app.config file of the test assembly.

Copy link

ghost commented May 4, 2022

seems like this will not work any more with specflow 3

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment