Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Composable fixtures support #3178

Open
neistow opened this issue Feb 15, 2025 · 3 comments
Open

Composable fixtures support #3178

neistow opened this issue Feb 15, 2025 · 3 comments
Labels

Comments

@neistow
Copy link

neistow commented Feb 15, 2025

Currently, the fixture requiring another fixture doesn't work, throwing an exception.

Xunit.Sdk.TestPipelineException
Class fixture type 'Playground.Tests.FixtureB' had one or more unresolved constructor arguments: FixtureA fixtureA
   at Xunit.v3.FixtureMappingManager.GetFixture(Type fixtureType) in /_/src/xunit.v3.core/Utility/FixtureMappingManager.cs:line 164
   at Xunit.v3.FixtureMappingManager.InitializeAsync(IReadOnlyCollection`1 fixtureTypes) in /_/src/xunit.v3.core/Utility/FixtureMappingManager.cs:line 224
public class FixtureA
{
    public string A { get; private set; }
    
    public FixtureA()
    {
        A = "Can";
    }
}

public class FixtureB : IClassFixture<FixtureA>
{
    public string B { get; private set; }
    
    public FixtureB(FixtureA fixtureA)
    {
        B = fixtureA.A + " we make this work?";
    }
}

public class MyTests : IClassFixture<FixtureB>
{
    private readonly FixtureB _fixtureB;

    public MyTests(FixtureB fixtureB)
    {
        _fixtureB = fixtureB;
    }

    [Fact]
    public void Test()
    {
        Assert.NotEmpty(_fixtureB.B);
    }
}

I'm trying to share and compose some functionality used across tests. The only sketchy way I found of doing this is using TestContext.Current.GetFixture, but this heavily relies on interface implementation order and just doesn't feel right.

public class FixtureA
{
    public string A { get; private set; }

    public FixtureA()
    {
        A = "Can";
    }
}

public class FixtureB : IAsyncLifetime
{
    public string B { get; private set; } = null!;

    public FixtureB()
    {
    }

    public async ValueTask InitializeAsync()
    {
        var fixtureA = await TestContext.Current.GetFixture<FixtureA>();
        ArgumentNullException.ThrowIfNull(fixtureA);

        B = fixtureA.A + " we make this work?";
    }

    public ValueTask DisposeAsync() => ValueTask.CompletedTask;
}

// will work ONLY if IClassFixture<FixtureA> is implemented before IClassFixture<FixtureB>
public class MyTests : IClassFixture<FixtureA>, IClassFixture<FixtureB>
{
    private readonly FixtureB _fixtureB;

    public MyTests(FixtureB fixtureB)
    {
        _fixtureB = fixtureB;
    }

    [Fact]
    public void Test()
    {
        Assert.NotEmpty(_fixtureB.B);
    }
}

Any chance it will be implemented in xUnit? Other language frameworks allow fixtures to request other fixtures (rstest, pytest) to form complex object initialization.

@bradwilson
Copy link
Member

No, we do not support this, and there is currently no plan to support this.

@neistow
Copy link
Author

neistow commented Feb 15, 2025

@bradwilson Thanks for the answer. I’d like to try and add support for this. Does it align with the current library priorities?

@bradwilson
Copy link
Member

I would be willing to look at a PR for this, yes. It's not currently a priority for me to work on, which is a great reason for someone else to do the work. 😂

@neistow neistow changed the title Fixtures can not request other fixtures Composable fixtures support Feb 16, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants