NUnit and the Values Attribute

By | October 18, 2010

This quick post is a little ditty about NUnit’s Values attribute, and how we can use it to help ensure our tests fully cover desired functionality.

 

Problem Space

Introduced in the 2.5 release as part of NUnit’s new parameterized test support, the Values attribute allows you to quickly up your test count with just the flick of an attribute. To demonstrate, let’s take hypothetical business object that does something based on some hypothetical enumeration, as in the code below.

using System;

namespace NUnitFun.ValueAttribute
{
    public enum SomeEnum
    {
        Unknown = 0,
        FirstBizState = 2,
        SecondBizState,
        ThirdBizState,
        FourthBizState,
        FifthBizState
    }
}

 

A contrived example that could definitely be coded better, but it gets the point across. To be complete, we should have tests that cover both the positive and negative cases, namely, that we do the right thing for FirstBizCase and that we do the right thing for every other biz case. This is where the range attribute comes into play. It allows us to write a couple of tests like below.

using System;
using NUnitFun.RangeAttribute;
using NUnit.Framework;

namespace NUnitFun.ValueAttribute.Tests
{
    [TestFixture]
    public class SomeBizObjectTests
    {
        [Test]
        public void BizActionTrueForFirstBizCaseTest()
        {
            SomeBizObject bizObject = new SomeBizObject();

            bool value = bizObject.DoSomeBizAction(SomeEnum.FirstBizState);

            Assert.That(value, Is.True);
        }

        [Test]
        public void BizActionFalseForAllButFirstBizCaseTest()
        {

        }
    }
}

 

The first test is straightforward, it’s the second test where things get interesting. Obviously it’s blank right now; the challenge here is that we know that for every other enumeration value, we want to return false. While we could hand-roll a test for each of the enumeration values, this is terribly tedious. This is where the Value attribute comes into play. We can spin up a test like the below code shows.

[Test]
public void BizActionFalseForAllButFirstBizCaseTest(
    [Values(
        SomeEnum.SecondBizState,
        SomeEnum.ThirdBizState,
        SomeEnum.FourthBizState,
        SomeEnum.FifthBizState)] SomeEnum whichCase)
{
    SomeBizObject bizObject = new SomeBizObject();

    bool value = bizObject.DoSomeBizAction(whichCase);

    Assert.That(value, Is.False);
}

 

The meaning is easy enough to intuit – we are telling NUnit to run our test for each of the values specified in the Values attribute, where each value is passed into the test method via the whichCase parameter. This gives us four tests for the price of one, as can be seen when we run the test.

freeTests

 

Obviously we’re not advocating blindly aiming for a high test count here, we’re merely pointing out one of the consequences of using the Values attribute. It gives us a bit more flexibility in our toolkit, and allows us to cover more business cases as we strive to make our software better.