Search code examples
c#xunit

Passing optional parameter to class fixture constructor in xunit


I have tests that use an existing fixture, and I want to add new tests that pass a parameter to the fixture for configuration. I want to use optional parameters to avoid breaking the existing tests. Unfortunately...

Tests that don't specify the fixture with arguments get this error: Class fixture type 'ContextFixture' had one or more unresolved constructor arguments: String options

public class ContextFixture : IDisposable
{
    public ContextFixture(string? options = default) {...}
}
public class SandboxContextFixture : ContextFixture, IDisposable
{
    public SandboxContextFixture() : base(options) {...}
}
public class ServiceTests : IClassFixture<ContextFixture>
{
    public ServiceTests(ContextFixture contextFixture) {...}
}
public class RepositoryTests : IClassFixture<SandboxContextFixture>
{
    public RepositoryTests(SandboxContextFixture fixture) {...}
}

Solution

  • xUnit has some strict rules about which type of parameters can be accepted in the public constructor of a fixture class; a IMessageSink and ITestContextAccessor. See source code on GitHub. Note that exception being thrown here because the string option in your code is not supported.

    To resolve, keep a default/parameterless public constructor on that ContextFixture class allowing it to be instantiated without parameters.

    Add a protected constructor with parameters to that ConstextFixture and let the derived SandboxContextFixture fixture class call that one from its default/parameterless constructor.

    public class ContextFixture
    {
        public ContextFixture()
        { }
    
        protected ContextFixture(string? options)
        { }
    }
    
    public class SandboxContextFixture : ContextFixture
    {
        public SandboxContextFixture() : base("some options value")
        { }
    }
    

    Optionally, in the ContextFixture class, the parameterless constructor can call the one with parameters.

    public class ContextFixture
    {
        public ContextFixture() : this(default)
        { }
    
        protected ContextFixture(string? options)
        {
            // ... 
        }
    }