Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 639
Konstantin Konstantinov Avatar asked Aug 15 '18 02:08

Konstantin Konstantinov


People also ask

What is xUnit Theory?

Fact vs Theory Tests The primary difference between fact and theory tests in xUnit is whether the test has any parameters. Theory tests take multiple different inputs and hold true for a particular set of data, whereas a Fact is always true, and tests invariant conditions.

Which attribute is used to mark a method as test method in xUnit?

This method is decorated with the Fact attribute, which tells xUnit that this is a test.

What is xUnit class fixture?

You can use the class fixture feature of xUnit.net to share a single object instance among all tests in a test class. We already know that xUnit.net creates a new instance of the test class for every test.


2 Answers

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));
    }
}
like image 108
Ywapom Avatar answered Oct 13 '22 23:10

Ywapom


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));
    }
}
like image 45
Abby Sui Avatar answered Oct 14 '22 00:10

Abby Sui