Reputation: 3095
We are upgrading from specflow 1.something to version 3.9.74. I'm having some trouble getting our custom TraceListener to work.
This is the code of the IRuntimePlugin:
using TechTalk.SpecFlow.Plugins;
using TechTalk.SpecFlow.Tracing;
using TechTalk.SpecFlow.UnitTestProvider;
[assembly: RuntimePlugin(typeof(SpecFlowTracerPlugin.SpecFlowTracerPlugin))]
namespace SpecFlowTracerPlugin
{
public class SpecFlowTracerPlugin : IRuntimePlugin
{
public void Initialize(RuntimePluginEvents runtimePluginEvents, RuntimePluginParameters runtimePluginParameters, UnitTestProviderConfiguration unitTestProviderConfiguration)
{
runtimePluginEvents.CustomizeTestThreadDependencies +=
(sender, args) => { args.ObjectContainer.RegisterTypeAs<SpecFlowTracer, ITraceListener>(); };
}
}
}
This is the code of the TraceListener
class (it uses our own tracing framework, filters out some noise, and ensures that the test output is written to the output while test is running, not only at the end):
public class SpecFlowTracer : ITraceListener
{
private readonly Trace _trace = new Trace("SpecFlow", "TestStep");
public void WriteTestOutput(string message) => Trace(message);
public void WriteToolOutput(string message) => Trace(message);
private void Trace(string message)
{
if (message.StartsWith("done: ")) return;
var context = FeatureContext.Current;
if (context != null)
{
message = $"{DateTime.Now:yy-MM-dd HH:mm:ss.fff}\t{context.FeatureInfo.Title}: {message}";
}
_trace.TraceInfo($"-> {message}");
// Next line is required to show progress while test is running
TestContext.Progress.WriteLine(message);
// Next line is required to show output in xml and other places
Console.WriteLine(message);
}
}
Both classes are defined in a class library that is used as a plugin by the main test project. In our specflow test project, the class library is is included as a reference. In the app.config file of the test project there used to be this code:
<specflow>
...
<plugins>
<add name="SpecFlowTracer" path="." type="Runtime" />
</plugins>
</specFlow>
However, this is no longer needed in specflow 3 according to the documentation (it doesn't even compile). Instead, plugins are detected automatically when their dll is present in the bin directory of the test project.
And indeed, when running a test with the debugger attached, I can see that the Initialize
method is called correctly, but the constructor of the SpecFlowTracer
class is never called (I checked by adding an empty default constructor with a breakpoint in it). It appears that the default implementation is still used.
I've also tried registering it using the following code in the IRuntimePlugin's Initialize
method:
public void Initialize(RuntimePluginEvents runtimePluginEvents, RuntimePluginParameters runtimePluginParameters, UnitTestProviderConfiguration unitTestProviderConfiguration)
{
runtimePluginEvents.RegisterGlobalDependencies += (sender, args) =>
{
args.ObjectContainer.RegisterTypeAs<SpecFlowTracer, ITraceListener>();
};
}
But that results in an exception being thrown:
BoDi.ObjectContainerException: 'An object has been resolved for this interface already.'
Update: I've tried the same with CustomizeGlobalDependencies
instead of RegisterGlobalDependencies
, but the same exception is throw.
When I inspect the registrations
property of the objectContainer
, I can see that there is indeed an existing registration for ITraceListener
: the TechTalk.SpecFlow.Tracing.DefaultTraceListener
.
What is the correct way to register a tracelistener?
Upvotes: 2
Views: 90