Michael
Michael

Reputation: 548

Proper way to conduct or quit a unit test based on a real-time value

I have a class that checks if the current day of the week is Wednesday. It looks like this:

public class Wednesday
{
    public string IsWednesday()
    {
        if (DateTime.Now.DayOfWeek == DayOfWeek.Wednesday)
        {
            return "It’s Wednesday";
        }
        else
        {
            return "It’s not Wednesday";
        }
    }
}

Don't worry about the return type, I know that it's bad in this particular example to return a magic string. We're focused on its purpose, not implementation.

I would love to cover it with unit tests for both cases of the current weekday being Wednesday and being anything but Wednesday.

I am new to unit testing and I'm wondering what the best solution would be in this example.

Right now, I'm using VS2019 with MS Test V2. I've tested both scenarios like this:

[TestClass]
public class WednesdayTests
{
    [TestMethod]
    public void IsWednesday_CurrentWeekDayIsWednesday_ReturnsItsWedndesday()
    {
        if (!(DateTime.Now.DayOfWeek == DayOfWeek.Wednesday))
        {
            return; 
        }

        // Arrange
        Wednesday wednesdayObj = new Wednesday();

        // Act
        string result = wednesdayObj.IsWednesday();

        // Assert
        Assert.AreEqual("It’s Wednesday", result);
    }

    [TestMethod]
    public void IsWednesday_CurrentWeekDayIsNotWednesday_ReturnsItsNotWednesday()
    {
        if (!(DateTime.Now.DayOfWeek != DayOfWeek.Wednesday))
        {
            return;
        }

        Wednesday wednesdayObj = new Wednesday();

        string result = wednesdayObj.IsWednesday();

        Assert.AreEqual("It’s not Wednesday", result);
    }
}

Is it considered OK to return out of a test method when some condition is not met, like in my case?

Or is there something inherently wrong with my solution?

Glad to hear any suggestions from experienced software developers!

P.S. Just noticed that the test will only be conducted if it's actually Wendesday :) Wow, that's for sure is not the solution!

Upvotes: 2

Views: 437

Answers (2)

Alberto Chiesa
Alberto Chiesa

Reputation: 7350

One of the fundamental principles of Unit Testing is that it should be repeatable and self-contained. Yours, as is, is not.

One way to make unit testable methods depending on current date is to feed them with a constant "now" value (a value provided by the test runner).

    public string IsWednesday() => IsWednesday(DateTime.Now);

    public string IsWednesday(DateTime time)
    {
        if (time.DayOfWeek == DayOfWeek.Wednesday)
        {
            return "It’s Wednesday";
        }
        else
        {
            return "It’s not Wednesday";
        }
    }

Then you can run the test with fixated dates, covering both cases "wednesday" and "not wednesday". This approach is an example of a general strategy: whatever is provided during normal execution by the environment (machine name, date, culture, etc) should be a parameter in the method under test, and the test bench should provide a range of significant values.

Regarding the actual tests (if I may, do yourself a favor and use NUnit or XUnit): they become trivial.

[TestMethod]
    public void ItsNotWednesday()
    {
        var wednesdayObj = new Wednesday();

        var result = wednesdayObj.IsWednesday(new DateTime(2019, 10, 5)); // Not a wednesday

        Assert.AreEqual("It’s not Wednesday", result);
    }

Upvotes: 1

Jocke
Jocke

Reputation: 2284

I would say it is bad practice to have return; in unit tests.

One of the biggest benefits with unit tests is that they make changing (read refactoring) the production code a straight forward process... and we don't want that process to be dependent on what weekday someone decides to change the code on.

If your test, and code, is dependent on time you need a way to control the clock in your test.

And in practice that mean that you need to hide the fact that your production code depends on DateTime.Now behind an abstraction that you can control in your test case.

Upvotes: 1

Related Questions