reqnroll / Reqnroll

Open-source Cucumber-style BDD test automation framework for .NET.
https://reqnroll.net
BSD 3-Clause "New" or "Revised" License
356 stars 38 forks source link

How to get IReqnrollOutputHelper in BeforeTestRun? #247

Closed Megadesty closed 1 month ago

Megadesty commented 1 month ago

Related Documentation Page

automation/hooks.md

Type of the problem

Missing information

Problem Description

In #59 it says:

This means that some services that were available so far for these hooks are not available anymore (e.g. "IReqnrollOutputHelper"), let's see the impact of this.

I just migrated to Reqnroll (awesome work btw!) and I'm impacted by this. Before I used the SpecFlowOutputHelper in a BeforeTestRun hook to configure some global services which

Is there any other way to get the output helper for global services?

gasparnagy commented 1 month ago

Not easy. I believe your solution was only working because you haven't used parallel execution (can you confirm?).

The challenge is that the test logging infrastructure provided by the test runners (mstest, nunit, xUnit) is bound to a test execution, so you cannot "remember" the output helper in a global service, because it would not know which test's logging infrastructure to be used. This is because if you run the tests parallel, there is no single "current" test, whose logging infrastructure could be used.

So basically what you did (because of the bug we fixed in #59) was picking the first execution worker thread and used the "current" test's logger within that worker thread.

If you would like to mimic the same behavior (that works only when you don't use parallel), you can do with a before scenario hook:

public static bool wasExecuted = false;
[BeforeScenario]
public static void ConfigureServices(ITestRunContext testRunContext, ITestThreadContext testThreadContext)
{
  if (wasExecuted) return;
  wasExecuted = true;

  var globalContainer = testRunContext.TestRunContainer; // this is the real global container used by all parallel threads
  var testThreadContainer = testThreadContext.TestThreadContainer; // this is what you have used in your hook
  //do service regs
}

For a real global service, all interfaces of your service should get the actual context and retrieve the output helper from it instead of storing it:

public class MyServiceClass {

  public void DoSomething(IScenarioContext context) {
    var outputHelper = context.ScenarioContainer.Resolve<IReqnrollOutputHelper>();
    //...
  }
}
Megadesty commented 1 month ago

Thank you very much for the detailed answer! You are right, the tests are executed sequentially. I guess it's the best to avoid logging in the way I did and maybe I can also activate parallel execution. Thanks again. I guess the docs doesn't need to be updated with this very specific topic so I close this issue.