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

Sunday, April 8, 2012

Migrating from NUnit to xUnit

I recently started using xUnit, and I have been really enjoying it!

If you are currently using NUnit to write your unit tests, then it is not at all difficult to migrate to using xUnit. The philosophical difference between the two is simply this: with xUnit you need to think of your tests as objects, rather than of methods. Or if you prefer acronyms: put some more OOP into your TDD. *bu-dum, tish!*

Anyway, here is a visual representation of equivalent commands between NUnit and xUnit:

xUnit

NUnit

[NUnit.Framework.TestFixture]
public class TestFixture
{
  [NUnit.Framework.TestFixtureSetUp]
  public void TestFixtureSetUp()
  {
    // 1) Set up test fixture  -------->
  }
  [NUnit.Framework.TestFixtureTearDown]
  public void TestFixtureTearDown()
  {
    // 8) Tear down test fixture  ----->
  }
 
 
 
  [NUnit.Framework.SetUp]
  public void SetUp()
  {
    // 2) Set up TestA  --------------->
    // 5) Set up TestB  --------------->
  }
  [NUnit.Framework.Test]
  public void TestA()
  {
    // 3) Run TestA  ------------------>
  }
  [NUnit.Framework.Test]
  public void TestB()
  {
    // 6) Run TestB.  ----------------->
  }
  [NUnit.Framework.TearDown]
  public void TearDown()
  {
    // 4) Tear down TestA  ------------>
    // 7) Tear down TestB  ------------>
  }
}
 
public class TestData : IDisposable
{
 
  public TestData()
  {
    // 1) Set up test fixture
  }
 
  public void Dispose()
  {
    // 8) Tear down test fixture
  }
}
public class TestClass
  : IDisposable, Xunit.IUseFixture
{
  public TestClass()
  {
    // 2) Set up TestA
    // 5) Set up TestB
  }
  [Xunit.Fact]
  public void TestA()
  {
    // 3) Run TestA
  }
  [Xunit.Fact]
  public void TestB()
  {
    // 6) Run TestB
  }
 
  public void Dispose()
  {
    // 4) Tear down TestA
    // 7) Tear down TestB
  }
  public TestData TestData { get; set; }
  public void SetFixture(TestData data)
  {
    // 2.5) Set fixture data for TestA
    // 5.5) Set fixture data for TestB
    TestData = data;
  }
}
kick it on DotNetKicks.com

Happy testing!
~Tom

Real Time Web Analytics