Logging with Specflow and xUnit 2 (ITestOutputHelper)
Asked Answered
C

4

8

Unfortunately I have a Specflow test passing locally, but it fails on the VSO Build vNext server, and I really need to see verbose information during the test run so I can figure out what is going on.

But I'm struggling to try to inject ITestOutputHelper into a Specflow binding like so

public SomeSteps(ITestOutputHelper outputHelper)

but Specflow complains with the message

BoDi.ObjectContainerException Interface cannot be resolved: Xunit.Abstractions.ITestOutputHelper (resolution path: ...)

How on earth can view log and view output during a Specflow test?

Complication answered 1/4, 2016 at 19:2 Comment(2)
can't you just Trace.WriteLine or Debug.WriteLine in your steps?Make
Described in the link that @Avalanchis provided in another comment. but unfortunately xUnit2 doesn't capture Trace and Debug output. You have to use ITestOutputHelper. [rant on] I'm starting to dislike xUnit.net more and more. Even on github there seems to be only a very few contributors and not many commits and replies to address the issues that have been reported. [rant off]Complication
P
3

not sure if I'm using a newer version and it's easier now, but this seems to work for me:

ScenarioContext.Current.ScenarioContainer.Resolve<ITestOutputHelper>().WriteLine("Hello");
Planetary answered 9/7, 2018 at 13:9 Comment(1)
This worked for me -- also note that you can obtain the ScenarioContext in via Dependency Injection (DI) in .NET Core instead of using ScenarioContext.Current.Perpetuate
L
2

This is the best I could come up with, it's not ideal but it does accomplish what you want.

You create a new class that implements your generated xunit class. In my example, the generated class is called YourNormalFeatureClass

public class SpecialTest : YourNormalFeatureClass
{
    private Xunit.Abstractions.ITestOutputHelper helper;

    public SpecialTest(ITestOutputHelper helper) : base()
    {
        this.helper = helper;   
    }

    public override void ScenarioSetup(ScenarioInfo scenarioInfo)
    {
        base.ScenarioSetup(scenarioInfo);

        // you'd want a better way to keep track of this string
        TechTalk.SpecFlow.TestRunnerManager.GetTestRunner().ScenarioContext.Set(this.helper, "helper");
    }

}

Now, you're able to access your XUnit ITestOutputHelper from within your steps file via

var helper = this._scenarioContext.Get<Xunit.Abstractions.ITestOutputHelper>("helper");
helper.WriteLine("output from within the steps file that will be written to xunit!");

You'd need to be defensive with that helper variable to make sure that you don't get any NullReferenceException's

The downside to this is that you now have 2 copies of the same test because you inherited the old test. So in this case you have the tests from SpecialTest and YourNormalFeatureClass. This means that you'd need to not run YourNormalFeatureClass tests and only run the SpecialTest tests.

All of this would be easily solved if SpecFlow allowed you to customize the code generation process. That way you could expose the ITestOutputHelper via the generated code. The consumption of it from within the steps would be the same.

Lionfish answered 3/11, 2016 at 0:1 Comment(2)
There's a pull request waiting since August which does exactly this: github.com/techtalk/SpecFlow/pull/689Delphinedelphinia
That's awesome, pitty they aren't pulling it inLionfish
V
1

This may be a new addition to SpecFlow since this question was asked (6 years ago), but TechTalk.SpecFlow.Infrastructure.ISpecFlowOutputHelper should solve your problem. Inject it and use it in much the same way you would with xUnit's ITestOutputHelper, e.g.

[Binding]
public class SomeSteps
{
    private readonly ISpecFlowOutputHelper output;

    public SomeSteps(ISpecFlowOutputHelper output)
    {
        this.output = output;
    }

    [When(@"I write some debug info")]
    public void WhenIWriteSomeDebugInfo()
    {
        this.output.WriteLine("Hello world!");
    }
}
Vierno answered 11/9, 2022 at 15:46 Comment(0)
B
0

Under the parallel-running framework you can't use a static ScenarioContext anymore, but you can use:

var console= _scenarioContext.ScenarioContainer.Resolve<ISpecFlowOutputHelper>();

Ref: https://docs.specflow.org/projects/specflow/en/latest/Execution/Parallel-Execution.html#xunit-configuration

Bellman answered 29/8, 2023 at 14:18 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.