2

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!

Michael
  • 548
  • 6
  • 23
  • 1
    I think quitting the UnitTest because it's the wrong day is a really bad solution since you can only test it on Wednesdays. What happens if you need to release a new version on Thursday? You could end up with broken code and not know it. I'd instead suggest using something like [Smocks](https://stackoverflow.com/a/36452202/3181933) to "mock" it, or abstract it (e.g. `IDateTime`) and just mock it using a regular mocking library such as Moq. – ProgrammingLlama Oct 05 '19 at 15:28
  • @John, yeah, just edited the question, that's a funny way of conducting tests :) I'll look up mocking, thanks! – Michael Oct 05 '19 at 15:30

2 Answers2

1

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.

Jocke
  • 2,189
  • 1
  • 16
  • 24
1

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);
    }
Alberto Chiesa
  • 7,022
  • 2
  • 26
  • 53