Navid_pdp11
Navid_pdp11

Reputation: 4032

How to inject dependencies into IClassFixture in XUnit?

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

Upvotes: 4

Views: 6516

Answers (2)

endurium
endurium

Reputation: 1021

To answer your question in the context of using XUnit.Di, it's not possible to inject a dependency via the test fixture constructor, because the fixture is being created by XUnit rather than the XUnit DI container. On the other hand, constructor dependency injection into test classes does work.

TBH, if you're using XUnit DI, you don't really need test fixtures as dependencies can be injected into the test class via DI rather than using fixtures, particularly useful for singleton dependencies.

The demos at https://github.com/clix455/Xunit.Di/blob/develop/GET-STARTED.md tell you everything you need to know about creating the container class and using it to register dependencies.

Upvotes: 1

cli
cli

Reputation: 382

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
    }
}

Upvotes: 1

Related Questions