NUnit parameterized tests with datetime

Unit TestingNunit

Unit Testing Problem Overview


Is it not possible with NUnit to go the following?

[TestCase(new DateTime(2010,7,8), true)]
public void My Test(DateTime startdate, bool expectedResult)
{
    ...
}

I really want to put a datetime in there, but it doesn't seem to like it. The error is:

> An attribute argument must be a constant expression, typeof expression > or array creation expression of an attribute parameter type

Some documentation I read seems to suggest you should be able to, but I can't find any examples.

Unit Testing Solutions


Solution 1 - Unit Testing

You can specify the date as a constant string in the TestCase attribute and then specify the type as DateTime in the method signature.

NUnit will automatically do a DateTime.Parse() on the string passed in.

Example:

[TestCase("01/20/2012")]
[TestCase("2012-1-20")] // Same case as above in ISO 8601 format
public void TestDate(DateTime dt)
{
    Assert.That(dt, Is.EqualTo(new DateTime(2012, 01, 20)));
}

Solution 2 - Unit Testing

I'd probably use something like the ValueSource attribute to do this:

public class TestData
{
    public DateTime StartDate{ get; set; }
    public bool ExpectedResult{ get; set; }
}

private static TestData[] _testData = new[]{
    new TestData(){StartDate= new DateTime(2010, 7, 8), ExpectedResult= true}};

[Test]
public void TestMethod([ValueSource("_testData")]TestData testData)
{
}

This will run the TestMethod for each entry in the _testData collection.

Solution 3 - Unit Testing

Another alternative is to use a more verbose approach. Especially if I don't necessarily know up front, what kind of DateTime() (if any...) a given string input yields.

[TestCase(2015, 2, 23)]
[TestCase(2015, 12, 3)]
public void ShouldCheckSomething(int year, int month, int day)
{
    var theDate = new DateTime(year,month,day);
    ....
} 

...note TestCase supports max 3 params so if you need more, consider something like:

private readonly object[] testCaseInput =
{
    new object[] { 2000, 1, 1, true, "first", true },
    new object[] { 2000, 1, 1, false, "second", false }
}

[Test, TestCaseSource("testCaseInput")]
public void Should_check_stuff(int y, int m, int d, bool condition, string theString, bool result)
{
....
}

Solution 4 - Unit Testing

You should use the TestCaseData Class as documented: http://www.nunit.org/index.php?p=testCaseSource&r=2.5.9

In addition to specifying an expected result, like:

 new TestCaseData(12, 4).Returns(3);

You can also specify expected exceptions, etc.:

 new TestCaseData(0, 0)
    .Throws(typeof(DivideByZeroException))
    .SetName("DivideByZero")
    .SetDescription("An exception is expected");

Solution 5 - Unit Testing

It seems that NUnit doesn't allow the initialization of non-primitive objects in the TestCase(s). It is best to use TestCaseData.

Your test data class would look like this:

public class DateTimeTestData
{
    public static IEnumerable GetDateTimeTestData()
    {
        // If you want past days.
        yield return new TestCaseData(DateTime.Now.AddDays(-1)).Returns(false);
        // If you want current time.
        yield return new TestCaseData(DateTime.Now).Returns(true);
        // If you want future days.
        yield return new TestCaseData(DateTime.Now.AddDays(1)).Returns(true);
    }
}

In your testing class you'd have the test include a TestCaseSource which directs to your test data.

How to use: TestCaseSource(typeof(class name goes here), nameof(name of property goes here))

[Test, TestCaseSource(typeof(DateTimeTestData), nameof(GetDateTimeTestData))]
public bool GetDateTime_GivenDateTime_ReturnsBoolean()
{
    // Arrange - Done in your TestCaseSource

    // Act
    // Method name goes here.

    // Assert
    // You just return the result of the method as this test uses ExpectedResult.
}

Solution 6 - Unit Testing

Nunit has improved and implicitly tries to convert the attribute arguments. See doc: NUnit3 Doc - see note

This works:

[TestCase("2021.2.1", ExpectedResult = false)]
[TestCase("2021.2.26", ExpectedResult = true)]
public bool IsDate(DateTime date) => date.Date.Equals(new DateTime(2021, 2, 26));

Take care to use english culture format for DateTime string arguments.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionAnonyMouseView Question on Stackoverflow
Solution 1 - Unit TestingRonnBlackView Answer on Stackoverflow
Solution 2 - Unit TestingShaun WildeView Answer on Stackoverflow
Solution 3 - Unit TestingCaad9RiderView Answer on Stackoverflow
Solution 4 - Unit TestingDoguhan UlucaView Answer on Stackoverflow
Solution 5 - Unit TestingAzzamAzizView Answer on Stackoverflow
Solution 6 - Unit TestingLakedaimonView Answer on Stackoverflow