Konstantin Konstantinov
Konstantin Konstantinov

Reputation: 1413

XUnit Theory-like data at the level of class, NOT method

  1. I use XUnit to run unit tests in C# code.
  2. I have many abstract unit tests classes, which take one standard extra fairly complicated parameter (in comparison to a standard XUnit test class setup).
  3. The values of that parameter come from some static list (for the simplicity of the example).
  4. I need to run all relevant unit test classes for all possible values of the parameter from that list and without repetitive boilerplate code.

In a sense this is equivalent to TheoryData, but applied at the level of test class rather than at the level of the method. Is this possible within current XUnit framework? If yes, then how exactly?

Upvotes: 8

Views: 4274

Answers (3)

komarik
komarik

Reputation: 93

Looks like inheritance should solve this:

public sealed class TestData { }
public abstract class BaseMyTests
{
    protected abstract TestData Data { get; }

    [Theory]
    [InlineData(1, 2)]
    [InlineData(5, 100)]
    public void Test1(int x, int y)
    {
        //...
    }

    [Fact]
    public void Test2()
    {
        //...
    }
}

public sealed class Group1Tests : BaseMyTests
{
    protected override TestData Data { get; } = new();
}

public sealed class Group2Tests : BaseMyTests
{
    protected override TestData Data { get; } = new();
}

Upvotes: 0

Abby Sui
Abby Sui

Reputation: 19

You can use IClassFixture. Create a customized TFixture to return data to your test class constructor.

namespace Xunit
{
    public interface IClassFixture<TFixture> where TFixture : class
    {
    }
}

And your method should inherit the customized fixture

public class ParameterizedTests: IClassFixture<TFixture>
{
    public ParameterizedTests(TFixture fixture)
    {
    }

    public bool IsOddNumber(int number)
    {
        return number % 2 != 0;
    }

    [Theory]
    [ClassData(typeof(TestDataGenerator))]
    public void AllNumbers_AreOdd_WithClassData(int a, int b, int c, int d)
    {
        Assert.True(IsOddNumber(a));
        Assert.True(IsOddNumber(b));
        Assert.True(IsOddNumber(c));
        Assert.True(IsOddNumber(d));
    }
}

Upvotes: 1

Ywapom
Ywapom

Reputation: 601

You can do it with a ClassData as mentioned here

You create some kind of Generator class like below and use the ClassData fixture with Theory.

public class TestDataGenerator : IEnumerable<object[]>
{
    private readonly List<object[]> _data = new List<object[]>
    {
        new object[] {5, 1, 3, 9},
        new object[] {7, 1, 5, 3}
    };

    public IEnumerator<object[]> GetEnumerator() => _data.GetEnumerator();

    IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}

public class ParameterizedTests
{
    public bool IsOddNumber(int number)
    {
        return number % 2 != 0;
    }

    [Theory]
    [ClassData(typeof(TestDataGenerator))]
    public void AllNumbers_AreOdd_WithClassData(int a, int b, int c, int d)
    {
        Assert.True(IsOddNumber(a));
        Assert.True(IsOddNumber(b));
        Assert.True(IsOddNumber(c));
        Assert.True(IsOddNumber(d));
    }
}

Upvotes: 3

Related Questions