Search code examples
c#nunitparameterized-unit-testnunit-2.6

Use Values- and Range-Attribute in NUnit TestFixture constructor


I have multiple test methods which should test all possible combinations of multiple parameters. I can use the NUnit ValueAttribute or RangeAttribute on methods like this:

[TestFixture]
public class MyExampleTests
{
    [Test]
    public void TestedEntity_GivenParemeter_Passes(
        [Values(1, 2)] int inputA,
        [Range(1, 4)] int inputB)
    {
        if (inputA > 0 && inputB > 0)
            Assert.Pass();
    }
}

However, in my real-world case there are 4 parameters, a dozen methods and more values, so it becomes tedious to write out all the values for every method and if I want to make a change, I might make a mistake somewhere.

How can I move the test generation for all value combinations away from the individual methods and into the TestFixture body? The following doesn't work, but it would be what I want:

[TestFixture]
public class MyExampleTests2
{
    readonly int inputA;
    readonly int inputB;

    public MyExampleTests2(
        [Values(1, 2)] int inputA,
        [Range(1, 4)] int inputB)
    {
        this.inputA = inputA;
        this.inputB = inputB;
    }

    [Test]
    public void TestedEntity_GivenParemeter_Passes()
    {
        if (this.inputA > 0 && this.inputB > 0)
            Assert.Pass();
    }
}

I already know that the TestFixtureAttribute can take parameters, but they don't work the way I want. I can only give each parameter a hardcoded value. Instead I want to use ranges and also let NUnit create a test for every combination. Also, I would like the solution to work in NUnit 2.6.4.


Solution

  • You can use ValuesSource:

    [Test]
    public void TestedEntity_GivenParemeter_Passes(
        [ValueSource(nameof(FirstSource))] int inputA,
        [ValueSource(nameof(SecondSource))] int inputB)
    {
        if (inputA > 0 && inputB > 0)
            Assert.Pass();
    }
    
    private static readonly int[] FirstSource = { 1, 2 };
    private static readonly IEnumerable<int> SecondSource = Enumerable.Range(1, 4);
    

    If you want to avoid the repetition of parameter declarations, you could create a single type containing properties for InputA and InputB, and a source which returned a sequence of that type.