Using ITestOutputHelper with Selenium, xUnit and C#

Viewed 2871

I have recently switched a project from NUnit to xUnit so that ITestOutputHelper can be used to output to a log.

The project is a fairly standard layout

Feature Files->Step Classes->Page Classes->Help Classes. Include in the helper classes we have the hooks.class also. I am using the xUnit runner.

So in my hooks class I have created this

private readonly ScenarioContext _scenarioContext;
private ITestOutputHelper _testOutputHelper;

public Hooks(ScenarioContext scenarioContext, ITestOutputHelper testOutputHelper)
{
    _scenarioContext = scenarioContext;
    this._testOutputHelper = testOutputHelper;
}

public void WriteOutput(string theMessage)
{
    _testOutputHelper.WriteLine(theMessage);
}

Now my question is how do I access the WriteOutput function from the other classes? Or have I placed it in the wrong class?

2 Answers

Since your hooks class already accepts an ITestOutputHelper object, your other step definitions need only do the same thing. From that point on it's just good old fashioned dependency injection.

If you initialize page models and utility classes in each step definition class, since it appears ITestOutputHelper is already registered in SpecFlow's dependency injection framework, you can just pass references to the helper from constructor to constructor.

For example, add a constructor arg and field to a step definition:

[Binding]
public class LoginSteps
{
    private ITestOutputHelper testOutputHelper;
    private LoginPage loginPage;
    private SomeUtility utility;

    public LoginSteps(IWebDriver driver, ITestOutputHelper testOutputHelper)
    {
        this.testOutputHelper = testOutputHelper;

        // Pass the test output helper to a page model
        loginPage = new LoginPage(driver, testOutputHelper);

        // Pass the test output helper to a utility class
        utility = new SomeUtility(testOutputHelper);
    }

    [Given(@"the user is logged in as ""(.*)"")")]
    public void GivenTheUserIsLoggedInAs(string username)
    {
        testOutputHelper.WriteLine("...");
        loginPage.LogIn(username);
    }
}

Then the page model and utility class need constructor args and fields:

public class LoginPage
{
    private IWebDriver driver;
    private ITestOutputHelper testOutputHelper;

    public LoginPage(IWebDriver driver, ITestOutputHelper testOutputHelper)
    {
        this.driver = driver;
        this.testOutputHelper = testOutputHelper;
    }

    // ...
}

public class SomeUtility
{
    private ITestOutputHelper testOutputHelper;

    public SomeUtility(ITestOutputHelper testOutputHelper)
    {
        this.testOutputHelper = testOutputHelper;
    }

    // ...
}

With the help of another Dev got the answer, see below

Step Class TestAppSteps

using Xunit.Abstractions;

[Binding]
public sealed class TestAppSteps : TestAppPage
{
    public TestAppSteps(ITestOutputHelper output) : base(output)
    {
    }

    code
}           

Page Class TestAppPage
using Xunit.Abstractions;

public class TestAppPage : PageAssertions
{

    public TestAppPage(ITestOutputHelper output) : base(output)
    {

    }
    
    code
}

Utility Class PageAssertions using Xunit.Abstractions;

public class PageAssertions : SharedClass
{
    public PageAssertions(ITestOutputHelper output) : base(output) { }

    code inc'
    WriteToReport("Pass: URL is correct");
}

Utility Class SharedClass using Xunit.Abstractions;

public abstract class SharedClass : OutputFunctions
{
    public SharedClass(ITestOutputHelper output) 
        : base(output)
    {
    }
    
    shared code including
    WriteToReport(GetTheCurrentMethod());
}   

Abstract Class OutputFunctions

using Xunit.Abstractions;

public abstract class OutputFunctions
{
    protected readonly ITestOutputHelper _output;

    public OutputFunctions(ITestOutputHelper output)
    {
        _output = output;
    }

    public void WriteToReport(string theMessage)
    {
        _output.WriteLine(theMessage);
    }
}
Related