SpecFlow icon indicating copy to clipboard operation
SpecFlow copied to clipboard

Documentation request: enhance plugin documentation for changing global dependencies

Open ghost opened this issue 2 years ago • 8 comments

Product:

  • [x] SpecFlow
  • [ ] SpecFlow+ Runner
  • [ ] SpecFlow+ LivingDoc
  • [ ] SpecMap

What is missing: I tried to change the default ITraceListener like so:

public class CustomTracerPlugin : IRuntimePlugin
{
    public void Initialize(
        RuntimePluginEvents runtimePluginEvents,
        RuntimePluginParameters runtimePluginParameters,
        UnitTestProviderConfiguration unitTestProviderConfiguration)
    {
        runtimePluginEvents.CustomizeGlobalDependencies += (_, args) => args.ObjectContainer.RegisterTypeAs<CustomTracer, ITraceListener>();
    }
}

The initialize function gets called and failes, because there is already a ITraceListener registered. Documentation should include an example on how to change default objects in the DI-container.

ghost avatar May 05 '22 08:05 ghost

You picked the one interface that can't really be overridden by plugins on another level than on Scenarios. We are using it for logging itself before the plugins are loaded.

What did you try to achieve?

SabotageAndi avatar May 05 '22 10:05 SabotageAndi

I see you set this in the NUnit plugin.

I would really like to reduce output to a bare minimum for running tests on gitlab for merge request tests.

Ideally we would like to only get output in the form: test X successful and the full output for failing tests.

ghost avatar May 05 '22 11:05 ghost

It would be all right to overwrite it on scenario level I don't need the output of all the successful steps. If I can overwrite it on scenario level and remove most of the output that would be perfect. We have a limit on the log size (trying to remove that, too).

ghost avatar May 05 '22 11:05 ghost

Did you try to turn the tracing off?

https://docs.specflow.org/projects/specflow/en/latest/Installation/Configuration.html#trace

If this is not enough, I think your requirement would be best solved, if you contribute it to SpecFlow. Either use the tracing configuration value in more places or add a new one for the log level.

SabotageAndi avatar May 05 '22 13:05 SabotageAndi

I did, here's my specflow.json:

{
    "language": {
        "feature": "de-DE"
    },
    "stepAssemblies": [
        {
            "assembly": "SomeAssembly"
        }
    ],
    "trace": {
        "traceSuccessfulSteps": false
    }
}

And I will think about your proposal.

ghost avatar May 05 '22 14:05 ghost

should I file a bug report because traceSuccessfulSteps has no effect?

ghost avatar May 06 '22 09:05 ghost

Before that, can you check your specflow.json file is in the output folder? To be sure where the error is.

SabotageAndi avatar May 06 '22 11:05 SabotageAndi

I came across this issue a few times while looking for a way to inject an ITraceListener to capture start/end of step logging. (we were previously using the <trace listener="..." /> config option in Specflow 2 but can't use that anymore with Specflow 3) Turns out that start/end of step logging is done using the ITraceListener instance of the "test thread" container. Reproducing our solution here just in case it helps the next person (although I'm not sure if this is a stable solution. It looks like the nunit/xunit/mstest plugins also override ITraceListener. I don't know if the order of loading their plugin and our own CustomTracerPlugin is well-defined):

using TechTalk.SpecFlow.Plugins;
using TechTalk.SpecFlow.Tracing;
using TechTalk.SpecFlow.UnitTestProvider;

[assembly: RuntimePlugin(typeof(CustomTracerPlugin))]

public class CustomTracerPlugin : IRuntimePlugin
{
    public void Initialize(
        RuntimePluginEvents runtimePluginEvents,
        RuntimePluginParameters runtimePluginParameters,
        UnitTestProviderConfiguration unitTestProviderConfiguration)
    {
        runtimePluginEvents.CustomizeTestThreadDependencies +=
            (s, ea) => ea.ObjectContainer.RegisterTypeAs<OurNameSpace.OurClassName, ITraceListener>();
    }
}

namespace OurNameSpace
{
    public class OurClassName : ITraceListener {
        // Implementation
    }
}

You picked the one interface that can't really be overridden by plugins on another level than on Scenarios. We are using it for logging itself before the plugins are loaded.

Before finding the above solution, I tried to override the ITraceListener instance in the global dependency injection container. Doing it via a runtime plugin did not work indeed. However, I did find a way using the specflow.json config. It looks like the JsonConfigurationLoader registers any (implementation, interface) pairs that are specified in runtime.dependencies. In our case, we got that to work with the following specflow.json:

{
  "$schema": "https://specflow.org/specflow-config.json",
  "runtime": {
    "missingOrPendingStepsOutcome": "Error",
    "dependencies": [
      {
        "type": "OurNameSpace.OurClassName, OurAssemblyName",
        "as": "TechTalk.SpecFlow.Tracing.ITraceListener, TechTalk.SpecFlow"
      }
    ]
  }
}

dennisschagt avatar Apr 27 '24 20:04 dennisschagt