Skip to main content

Dealing with time

The problem​

Sometimes code is time sensitive. Consider the following method:

Greeter.cs
public string GenerateGreetText()
{
var dateTimeNow = DateTime.Now;
return dateTimeNow.Hour switch
{
>= 5 and < 12 => "Good morning",
>= 12 and < 18 => "Good afternoon",
_ => "Good evening"
};
}

This method uses the current time of your workstation to determine whether it is morning, afternoon or evening and produce a message.

Attempting to write unit tests for this method would be impossible. If you had 1 test per usecase then only one test out of 3 would pass at one time.

The solution​

In order to solve this problem we need to make the date time provider mockable. To achieve that let's create an interface.

public interface IDateTimeProvider
{
DateTime Now { get; }
}

The implementation will simply point to the same property invocation:

public class DateTimeProvider : IDateTimeProvider
{
public DateTime Now => DateTime.Now;
}

We can now write a unit test that mocks the IDateTimeProvider that we just created and returns a given date per test.

Exercise​

Implement 3 tests:

  • GenerateGreetText_ShouldReturnGoodMorning_WhenItsMorning
  • GenerateGreetText_ShouldReturnGoodAfternoon_WhenItsAfternoon
  • GenerateGreetText_ShouldReturnGoodEvening_WhenItsEvening

Expand any of the code blocks below to see the solution to the exercise but you are highly encouraged to implement the tests on your own.

GenerateGreetText_ShouldReturnGoodMorning_WhenItsMorning
[Fact]
public void GenerateGreetText_ShouldReturnGoodMorning_WhenItsMorning()
{
// Arrange
_dateTimeProvider.Now.Returns(new DateTime(2022, 1, 1, 9, 0, 0));

// Act
var message = _greeter.GenerateGreetText();

// Assert
message.Should().Be("Good morning");
}
GenerateGreetText_ShouldReturnGoodAfternoon_WhenItsAfternoon
[Fact]
public void GenerateGreetText_ShouldReturnGoodAfternoon_WhenItsAfternoon()
{
// Arrange
_dateTimeProvider.Now.Returns(new DateTime(2022, 1, 1, 15, 0, 0));

// Act
var message = _greeter.GenerateGreetText();

// Assert
message.Should().Be("Good afternoon");
}
GenerateGreetText_ShouldReturnGoodEvening_WhenItsEvening
[Fact]
public void GenerateGreetText_ShouldReturnGoodEvening_WhenItsEvening()
{
// Arrange
_dateTimeProvider.Now.Returns(new DateTime(2022, 1, 1, 20, 0, 0));

// Act
var message = _greeter.GenerateGreetText();

// Assert
message.Should().Be("Good evening");
}