I found a good use for the InlineData xUnit attribute:

public class DateDiffCalculatorFacts
{
    [Theory,
    InlineData("2008-09-25 14:31", "1 minute"),
    InlineData("2008-09-25 15:05", "35 minutes"),
    InlineData("2008-09-25 16:05", "1 hour 35 minutes"),
    InlineData("2008-09-25 17:05", "2 hours 35 minutes"),
    InlineData("2008-09-25 19:05", "4 hours"),
    InlineData("2008-09-25 02:30", "12 hours"),
    InlineData("2008-09-24 00:00", "1 day 14 hours"),
    InlineData("2008-09-23 00:00", "2 days 14 hours"),
    InlineData("2008-09-20 00:00", "5 days"),
    InlineData("2008-08-20 00:00", "1 month 5 days"),
    InlineData("2008-07-01 00:00", "2 months 24 days"),
    InlineData("2008-05-01 00:00", "4 months"),
    InlineData("2007-07-20 00:00", "1 year 2 months"),
    InlineData("2005-07-20 00:00", "3 years")]
    public void Can_get_correct_age_for_date(string dateString, string expectedAge)
    {
        var date = DateTime.Parse(dateString, CultureInfo.InvariantCulture, DateTimeStyles.None);
        var referenceDate = DateTime.Parse("2008-09-25 14:30:00", CultureInfo.InvariantCulture, DateTimeStyles.None);

        var calc = new DateDiffCalculator(date, referenceDate);

        string age = calc.ToString();
        Assert.Equal(expectedAge, age);
    }
}

This is the first time I have used this style of testing (called RowTests in MbUnit/NUnit). Maybe in this case it is not the right thing to do from a pure TDD perspective as the test name is not very descriptive of what is being tested. If each InlineData was extracted to a sepereate test they could be given more meaningfull names like "Measure_will_be_in_plural_when_more_than_one" and "Skip_sub_measure_when_main_measure_is_higher_than_two". On the otherhand having the test like above made it dead simple and fast to add new test cases and it still quite apparenent what the intended outcome is.

5 comments:

Colin Jack said...

I wouldn't fight it, if combanitorial/parameterized testing suits the situations then I think its right to use it and this seems like a good use.

Jeff Brown said...

This is a good use of a parameterized test.

MbUnit's [Row] attribute allows you to specify a Description for each test so you can include a more descriptive name for each case if you like. I think xUnit.Net and NUnit also support this behavior.

Pete said...

For that test, you might want to look at xUnit's FreezeClock feature - http://agileprogrammer.com/dotnetguy/archive/2007/11/11/23751.aspx :)

Torkel Ödegaard said...

I don't think the FreezeClock feature is that well suited, I need a fixed reference date, otherwise each date in each InlineData argument need to be compensated, it would just complicate things.

Peter Gfader said...

I want to have that in Visual Studio unit tests!!!
:-(