Dealing With Date/Time In Solitary Tests
Tags: unittests, tdd, testing, softwaredesign
Published: 2020-08-04 18:28:56

[Solitary tests](https://principal-it.eu/2019/10/taxonomy-of-tests/) never cross the process boundary in which they are executed. This means that a solitary test never executes code that talks to a database, communicates across the network, touches the file system, etc. This also implies that a solitary test never deals with the system clock either, whether it’s directly or indirectly.

Let’s have a look at some example code in order to grasp the implications of this.

```csharp
public class CreateCouponHandler
{
    private readonly ICouponRepository _couponRepository;

    public CreateCouponHandler(ICouponRepository couponRepository)
    {
        _couponRepository = couponRepository;
    }

    public void Handle_Coupled(CreateCoupon command)
    {
        var coupon = new Coupon(command.CouponCode, DateTime.Today);
        _couponRepository.Save(coupon);
    }
}

public class CreateCoupon
{
    public string CouponCode { get; }

    public CreateCoupon(string couponCode)
    {
        CouponCode = couponCode;
    }
}

```

Here we have a handler that creates a new discount coupon and saves it in the database. A coupon requires a code, and a creation date. The coupon code is specified through an incoming _CreateCoupon_ command object. The creation date is set to the current date by calling the _DateTime.Today_ static property.

Let’s have a look at the test code.

```csharp
[Specification]
public class When_creating_a_new_coupon
{
    [Establish]
    public void Context()
    {
        _couponRepository = Substitute.For<ICouponRepository>();
        _sut = new CreateCouponHandler(_couponRepository);
    }

    [Because]
    public void Of()
    {
        var command = new CreateCoupon("COUPON_CODE");
        _sut.Handle(command);
    }
    
    [Observation]
    public void Then_a_newly_created_coupon_should_be_saved()
    {
        var expectedCouponToBeSaved = new Coupon("COUPON_CODE", DateTime.Today);
        _couponRepository.Should_have_received(expectedCouponToBeSaved);        
    }

    private ICouponRepository _couponRepository;
    private CreateCouponHandler _sut;
}

```

According to its definition, this test doesn’t entirely qualify as a solitary test. Sure, it doesn’t require any external configuration file in order for it to execute properly. However, both the implementation and the test code have a direct dependency on the system clock.

This test will pass most of the time. However, on rare occasions this test might also fail. Why? Suppose that this testis being executed on a build server a couple of milliseconds before midnight. The call to _DateTime.Today_ in the _Handle_method of the _CreateCouponHandler_ class returns the current date. When the test method itself is executed, midnight has already passed. So the call to _DateTime.Today_ returns the date of the next day which causes the test to fail.

I do recognise that the chances are pretty slim for this to actually happen. Nonetheless, this definitely affects the reliability of the test. Suppose that besides the date, we also need to store the time when a coupon gets created. In that case, we would replace the calls to _DateTime.Today_ with _DateTime.UtcNow_. This would also make the test even less deterministic as it would sometimes fail due to a potential difference of just a couple of milliseconds.

In order to make both the implementation and the test code more loosely coupled, we could remove the direct dependency on the system clock by encapsulating the calls to _DateTime.Today_ and _DateTime.UtcNow_.

```csharp
public interface IClock
{
    DateTime GetCurrentDate();
    DateTime GetCurrentDateTime();
}

```

Here we’ve defined an interface named _IClock_. This defines a contract for retrieving the current date, or the current date/time.

```csharp
public class SystemClock : IClock
{
    public DateTime GetCurrentDate()
    {
        return DateTime.Today;
    }

    public DateTime GetCurrentDateTime()
    {
        return DateTime.UtcNow;
    }
}

```

The _SystemClock_ class provides an implementation of the _IClock_ interface by encapsulating the calls to _DateTime.Today_ and _DateTime.UtcNow_.

```csharp
public class CreateCouponHandler
{
    private readonly ICouponRepository _couponRepository;
    private readonly IClock _clock;

    public CreateCouponHandler(ICouponRepository couponRepository, IClock clock)
    {
        _couponRepository = couponRepository;
        _clock = clock;
    }

    public void Handle(CreateCoupon command)
    {
        var creationDate = _clock.GetCurrentDate();
        
        var coupon = new Coupon(command.CouponCode, creationDate);
        _couponRepository.Save(coupon); 
    }
}

```

An instance of the _IClock_ interface is injected into the constructor of the _CreateCouponHandler_ class. The IoC container of the application will provide the necessary instance of the _SystemClock_ class. In order to get the current date, we just call the _GetCurrentDate_ method.

Let’s see what this means for our test code.

```csharp
[Specification]
public class When_creating_a_new_coupon
{
    [Establish]
    public void Context()
    {
        _couponRepository = Substitute.For<ICouponRepository>();

        // The clock stub returns a concrete date
        var clock = Substitute.For<IClock>();
        clock.GetCurrentDate().Returns(new DateTime(2020, 08, 01));
        
        _sut = new CreateCouponHandler(_couponRepository, clock);
    }

    [Because]
    public void Of()
    {
        var command = new CreateCoupon("COUPON_CODE");
        _sut.Handle(command);
    }
    
    [Observation]
    public void Then_a_newly_created_coupon_should_be_saved()
    {
        // Here we specify a concrete date for the creation date
        var expectedCouponToBeSaved = new Coupon("COUPON_CODE", new DateTime(2020, 08, 01));
        _couponRepository.Should_have_received(expectedCouponToBeSaved);        
    }

    private ICouponRepository _couponRepository;
    private CreateCouponHandler _sut;
}

```

Notice that we no longer have a dependency on _DateTime.Today_ inside the test method. Instead, we just specify a concrete date.

```csharp
var expectedCouponToBeSaved = new Coupon("COUPON_CODE", new DateTime(2020, 08, 01));
_couponRepository.Should_have_received(expectedCouponToBeSaved);

```

In the setup of the test context, we also specify that a call to the _GetCurrentDate_ method would returnthe same concrete date.

```csharp
var clock = Substitute.For<IClock>();
clock.GetCurrentDate().Returns(new DateTime(2020, 08, 01));

```

By removing the direct dependency on the system clock, we turned our test into a full-fledged solitary test. Not only that. We’ve also made the test itself more deterministic as well. The test no longer suffers from potential failures depending on the time of day that it’s being executed. And then there’s also the aspect of readability.

Making use of _DateTime.Today_ or _DateTime.UtcNow_ lacks readability as a developer has to mentally translate this to a concrete date. Removing this mental translation step just makes things more convenient for other developers on the team.Especially when there’s some kind of date arithmetic involved, making use of a concrete date and/or time communicates more clearly what the inputs are and what the expected outputs should be.