Reputation: 548
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
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
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