Saturday, April 14, 2012

xUnit Theory, the Data Driven Unit Test

Update: I have also written a post about NUnit's Data Driven TestCaseAttribute.

Do you like copying and pasting code? Neither do I.

A good set of unit tests often end up reusing the same code with varied inputs. Rather than copy and paste that test code over and over, we can use the pattern of data driven unit tests to help streamline our test fixtures. This is the practice of having a single test definition be invoked and count as multiple tests at run time. This also enables us to do other dynamic things, such as configuring our unit tests from external sources. :)

I frequently use MSTest, but it's data driven tests inconveniently require you to define a DataSource. (Updated) Come to find out NUnit does offer data driven unit tests with their TestCaseSource attribute. Meanwhile xUnit offers several lightweight and simple options for defining data driven tests, which it refers to as theories.

Let's take a look at some of xUnit's Theory data sources:

InlineData Example

public class StringTests1
{
    [Theory,
    InlineData("goodnight moon", "moon", true),
    InlineData("hello world", "hi", false)]
    public void Contains(string input, string sub, bool expected)
    {
        var actual = input.Contains(sub);
        Assert.Equal(expected, actual);
    }
}

PropertyData Example

public class StringTests2
{
    [Theory, PropertyData("SplitCountData")]
    public void SplitCount(string input, int expectedCount)
    {
        var actualCount = input.Split(' ').Count();
        Assert.Equal(expectedCount, actualCount);
    }
 
    public static IEnumerable<object[]> SplitCountData
    {
        get
        {
            // Or this could read from a file. :)
            return new[]
            {
                new object[] { "xUnit", 1 },
                new object[] { "is fun", 2 },
                new object[] { "to test with", 3 }
            };
        }
    }
}

ClassData Example

public class StringTests3
{
    [Theory, ClassData(typeof(IndexOfData))]
    public void IndexOf(string input, char letter, int expected)
    {
        var actual = input.IndexOf(letter);
        Assert.Equal(expected, actual);
    }
}
 
public class IndexOfData : IEnumerable<object[]>
{
    private readonly List<object[]> _data = new List<object[]>
    {
        new object[] { "hello world", 'w', 6 },
        new object[] { "goodnight moon", 'w', -1 }
    };
 
    public IEnumerator<object[]> GetEnumerator()
    { return _data.GetEnumerator(); }
 
    IEnumerator IEnumerable.GetEnumerator()
    { return GetEnumerator(); }
}
kick it on DotNetKicks.com

Happy testing!
Tom

13 comments:

  1. Update! NUnit does offer data driven unit tests. Thanks to Mr. Weller for pointing this out.

    ReplyDelete
  2. I just implemented the "Or this could read from a file" part, feel free to copy/paste. In the file below, search the "TestServers" method and check the class comment for the JSON format sample:
    https://github.com/nicolas-raoul/CmisSync/blob/master/SparkleShare/TestLibrary/CmisSyncTests.cs
    Maybe CSV would have been more appropriate than JSON?

    ReplyDelete
  3. I have used the PropertyData with Theory attributes and it passes my tests but then says method "cannot have parameters". Have you seen this?

    ReplyDelete
  4. More elegant approach will be to `yield return new object[]`.
    I think this is the reason the property to have its return type IEnumerable rather than just array.

    ReplyDelete
  5. I read that Post and got it fine and informative. Please share more like that... ovulation test

    ReplyDelete
  6. This is such a great resource that you are providing and you give it away for free. I love seeing blog that understand the value of providing a quality resource for free. Tableau Data Blending

    ReplyDelete
  7. This comment has been removed by the author.

    ReplyDelete
  8. If you want to learn Primavera P6 Fundamentals then I would love to recommend you to visit PPM global services. Primavera P6 is the new version and PPM global services providing the best trainer for this. You will get all the basics to advance things from here.

    ReplyDelete
  9. Using the example above, let's plug multiple choice answers into one of the questions:are you dumb

    ReplyDelete
  10. Thanks for sharing the good information about the AI. It is an Excellent Blog. CoinPayments Verified Account

    ReplyDelete
  11. Using the example above, let's plug multipleCracksloo choice answers into one of the questions

    ReplyDelete

Real Time Web Analytics