How to inject dependencies into IClassFixture in XUnit?

Viewed 986

I am using XUnit and need to perform some action before running a test suit. so, I try to use IClassFixture feature of XUnit. but I cannot find a way to inject dependencies into the Fixture class. my code structure is such as below:

public class MyFixture
{
    IDependency _dep;

    public MyFixture(IDependency dep)
    {
        _dep = dep;
    }
    
    void DoSomeJob()
    {
       //// some code there
       dep.DoSome();
    } 
}  

And this is my test class code:

public class MyTest : IClassFixture<MyFixture>
{
    [Fact]
    public void test_my_code()
    {
        ////simply just test the code
    }
}

but when I run the test I am getting the exception

Xunit.Sdk.TestClassException Class fixture type 'MyFixture' had one or more unresolved constructor

1 Answers

Your Fixture class depends on IDependency dep, which has not been configured. You could use the Fixture class to setup a service provider; However it is not the best solution, as you have to end up using service locator patter such as

serviceProvider.GetRequiredService<T>()

Suggest to use xunit.di, it is an extension built into xunit framework to support constructor dependency injection, which allows us to achieve Inversion of Control (IoC) between test classes and their dependencies.

Install-Package Xunit.Di

To use xunit.di:

  • Install the xunit.di nuget package
  • Create a Setup.cs class to configure dependencies, (optional) and inherits the Xunit.Di.Setup.cs
  • Configure dependencies in the Setup.cs class.

Find full instructions and demos from xunit.di GET-STARTED

Your test project has the following:

  • Setup class that has a public IServiceProvider, which configures all the dependencies
  • Test class with constructor injecting the dependencies

Your Setup.cs class looks like below:

    private IServiceProvider _services;
    private bool _built = false;
    private readonly IHostBuilder _defaultBuilder;

    public Setup()
    {
        _defaultBuilder = Host.CreateDefaultBuilder();
    }

    public IServiceProvider Services => _services ?? Build();

    private IServiceProvider Build()
    {
        if (_built)
            throw new InvalidOperationException("Build can only be called once.");
        _built = true;

        _defaultBuilder.ConfigureServices((context, services) =>
        {
            services.AddSingleton<TextReaderService>();
            services.AddSingleton<IDependency, DependencyImpl>();
            // where DependencyImpl implements IDependency
            // ... add other services needed
        });

        _services = _defaultBuilder.Build().Services;
        return _services;
    }

Then your test class looks like below:

public class MyTest
{
    private readonly IDependency _dependency;

    public MyTest(IDependency dependency)
    {
        _dependency = dependency;
    }

    [Fact]
    public void test_my_code()
    {
        var result = _dependency.DoStuff();
        Assert.NotNull(result);
        ////simply just test the code
    }
}
Related