Test Doubles
Tags: unittests, tdd, testing, softwaredesign
Published: 2020-04-08 08:53:05

In the previous blog post, we’ve talked about [indirect inputs and outputs](https://principal-it.eu/2020/04/indirect-inputs-and-outputs/) when a unit test exercises a Subject Under Test. The examples shown previously demonstrate the use of test doubles.

A test double is a type of object that replaces a real instance of a collaborator, for the specific purpose of executing tests. Test doubles make it more easy for us to manipulate indirect inputs and verify indirect outputs. But this ease of use also comes with a certain cost. Depending on the type of test double being used, it also couples unit tests more tightly to their Subject Under Test, unless specific measures are applied to somewhat mitigate this coupling.

Test doubles are put in place using a technique called [Dependency Injection](https://bit.ly/dep-inj2). Instead of letting the Subject Under Test directly create an instance for each of its collaborators, these instances are provided from the outside. They are usually specified as arguments to the constructor of the Subject Under Test.

Let’s have a look at the different kinds of test doubles and their use.

#### Dummy

The first type of test double is called a _Dummy_. A _Dummy_ object supports some kind of interface that is expected by the Subject Under Test, but it doesn’t provide any behaviour or return any values. Basically, it doesn’t do anything. It just exists. A _Dummy_ is most often passed as a placeholder argument, but is never actually used by the Subject Under Test.

Let’s have a look at an example of a _Dummy_.

```csharp
public class CreateExpenseSheetHandler : ICommandHandler<CreateExpenseSheet>
{
    private readonly IEmployeeRepository _employeeRepository;
    private readonly IExpenseSheetRepository _expenseSheetRepository;

    public CreateExpenseSheetHandler(
        IEmployeeRepository employeeRepository,
        IExpenseSheetRepository expenseSheetRepository)
    {
        _employeeRepository = employeeRepository;
        _expenseSheetRepository = expenseSheetRepository;
    }
    
    public Result Handle(CreateExpenseSheet command)
    {
        if(null == command)
            throw new ArgumentNullException(nameof(command));

        var employee = _employeeRepository.Get(command.EmployeeId);
        if(null == employee)
        {
            var message = $"The employee with identifier '{command.EmployeeId}' could not be found.";
            return Result.Failure(new DomainViolation(message));    
        }
        
        var expenseSheet = new ExpenseSheet(command.Id, employee, command.SubmissionDate);
        _expenseSheetRepository.Save(expenseSheet);
        
        return Result.Success();
    }
}

public class CreateExpenseSheet
{
    public Guid Id { get; }
    public Guid EmployeeId { get; }
    public DateTime SubmissionDate { get; }
    
    public CreateExpenseSheet(Guid id, Guid employeeId, DateTime submissionDate)
    {
        Id = id;
        EmployeeId = employeeId;
        SubmissionDate = submissionDate;
    }
}

```

Here we have the implementation of a command handler that creates a new expense sheet. The command object specifies the identifier for the new expense sheet, the identifier of the employee and a submission date. We use the _Employee_ repository to retrieve an _Employee_ object based on its unique identifier. We let the operation fail in case the required _Employee_ object could not be found. Then the new _ExpenseSheet_ object is created and saved into the repository. In that case, the operation is completed successfully. Note that a guard condition has also been added in order to enforce the caller of the _Handle_ method to provide an instantiated _CreateExpenseSheet_ command object.

```csharp
public class DummyEmployeeRepository : IEmployeeRepository
{
    public Employee Get(Guid id)
    {
        throw new NotImplementedException(
            "The Get method of the EmployeeRepository shouldn't get called.");
    }
}

public class DummyExpenseSheetRepository : IExpenseSheetRepository
{
    public ExpenseSheet Get(Guid id)
    {
        throw new NotImplementedException(
            "The Get method of the ExpenseSheetRepository shouldn't get called.");
    }

    public void Save(ExpenseSheet expenseSheet)
    {
        throw new NotImplementedException(
            "The Save method of the ExpenseSheetRepository shouldn't get called.");
    }
}

```

The _DummyEmployeeRepository_ class provides a dummy implementation by implementing the _IEmployeeRepository_ interface. The _Get_ method throws a _NotImplementedException_ in case it gets called. The same is true for the _Get/Save_ methods of the _DummyExpenseSheetRepository_ class.

```csharp
[Specification]
public class When_creating_a_new_expense_sheet_using_a_non_existent_command
{
    [Establish]
    public void Context()
    {
        var dummyEmployeeRepository = new DummyEmployeeRepository();
        var dummyExpenseSheetRepository = new DummyExpenseSheetRepository();
        
        _sut = new CreateExpenseSheetHandler(dummyEmployeeRepository, dummyExpenseSheetRepository);
    }

    [Because]
    public void Of()
    {
        _createExpenseSheet = () => _sut.Handle(null);
    }
    
    [Observation]
    public void Then_an_exception_should_be_thrown()
    {
        Assert.That(_createExpenseSheet, Throws.ArgumentNullException);
    }
    
    private CreateExpenseSheetHandler _sut;
    private TestDelegate _createExpenseSheet;
}

```

This particular test scenario verifies whether an _ArgumentNullException_ is thrown by the Subject Under Test when a null reference is passed to the _Handle_ method. We pass an instance of both the _DummyEmployeeRepository_ and the _DummyExpenseSheetRepository_ classes to the constructor of the _CreateExpenseSheetHandler_.

We could also get away with just passing two null references instead of these dummy objects. But then we just get a _NullReferenceException_ when the test fails. Using an actual dummy implementation results in slightly more meaningful diagnostic information due to the custom exception messages in each method. Implementing and using a dummy object this way, we can ensure that a collaborator is never used in a particular scenario.

#### Stub

The second type of test double is called a _Stub_. A _Stub_ object is the same as a _Dummy_. It doesn’t do anything, except providing the Subject Under Test an indirect input that can be controlled by a test. So, the only thing a _Stub_ does more than a _Dummy_ is returning values for query methods. A test can instruct a _Stub_ to return either a valid or an invalid indirect input depending on the test scenario. But it can also instruct a _Stub_ to raise a particular exception as well.

Let’s have a look at an example of a _Stub_.

```csharp
public class StubEmployeeRepository : IEmployeeRepository
{
    private readonly Employee _result;

    public StubEmployeeRepository(Employee result)
    {
        _result = result;
    }
    
    public Employee Get(Guid id)
    {
        return _result;
    }
}

```

The _StubEmployeeRepository_ class implements the _IEmployeeRepository_ interface. Its constructor expects an instance of an _Employee_ that can be returned by the _Get_ method when and if called.

```csharp
[Specification]
public class When_creating_a_new_expense_sheet_for_an_unknown_employee 
{
    [Establish]
    public void Context()
    {
        Employee unknownEmployee = null;
        
        var stubEmployeeRepository = new StubEmployeeRepository(unknownEmployee);
        var dummyExpenseSheetRepository = new DummyExpenseSheetRepository();
        
        _sut = new CreateExpenseSheetHandler(stubEmployeeRepository, dummyExpenseSheetRepository);
    }
    
    [Because]
    public void Of()
    {
        var command = new CreateExpenseSheet(Guid.NewGuid(), Guid.NewGuid(), new DateTime(2018, 11, 11));
        _result = _sut.Handle(command);
    }
    
    [Observation]
    public void Then_the_operation_should_fail()
    {
        Assert.That(_result.IsSuccessful, Is.False);
    }

    private CreateExpenseSheetHandler _sut;
    private Result _result;
}

```

The test scenario verifies whether the operation fails when the specified employee could not be found by the repository. This means that the stubbed _EmployeeRepository_ returns a null reference when the _Get_ method is called by the _CreateExpenseSheetHandler_. Further execution of the _Handle_ method should be aborted. This is enforced by using a dummy implementation of the _ExpenseSheetRepository_.

A _Stub_ is usually the type of Test Double that is most often used throughout an entire suite of unit tests.

#### Spy

The third type of test double is called a _Spy_. A _Spy_ does the same things as a _Stub_. It provides returns values for the query methods of its public interface. But a _Spy_ also captures the indirect outputs of the Subject Under Test and afterwards provides the ability for the test to verify these outputs. This is for the command methods of the public interface that it supports.

Let’s have a look at an example of a _Spy_.

```csharp
public class SpyExpenseSheetRepository : IExpenseSheetRepository
{
    private readonly ExpenseSheet _result;
    
    public ExpenseSheet SavedExpenseSheet { get; private set; }
    
    public SpyExpenseSheetRepository(ExpenseSheet result)
    {
        _result = result;
    }
    
    public ExpenseSheet Get(Guid id)
    {
        return _result;
    }

    public void Save(ExpenseSheet expenseSheet)
    {
        SavedExpenseSheet = expenseSheet;
    }
}

```

The _SpyExpenseSheetRepository_ class implements the _IExpenseSheetRepository_ interface. The constructor of the spy expects an instance of an _ExpenseSheet_ that can be returned by the _Get_ method when and if called. But it also assigns the _ExpenseSheet_ object that is specified to the _Save_ method in the _SavedExpenseSheet_ public property.

```csharp
[Specification]
public class When_creating_a_new_expense_sheet__spy_example
{
    [Establish]
    public void Context()
    {
        var employee = Example.Employee().WithId(new Guid("680D0C0A-E445-4344-B67A-363589E2746A"));
        
        var stubEmployeeRepository = new StubEmployeeRepository(employee);
        _spyExpenseSheetRepository = new SpyExpenseSheetRepository(null);
        
        _sut = new CreateExpenseSheetHandler(stubEmployeeRepository, _spyExpenseSheetRepository);
    }

    [Because]
    public void Of()
    {
        var command = new CreateExpenseSheet(
            new Guid("4048A482-1CBA-45AA-8709-6409B9FD32E3"), 
            new Guid("680D0C0A-E445-4344-B67A-363589E2746A"), 
            new DateTime(2018, 11, 11));

        _result = _sut.Handle(command);
    }
    
    [Observation]
    public void Then_the_approved_expense_sheet_should_be_saved()
    {
        var savedExpenseSheet = _spyExpenseSheetRepository.SavedExpenseSheet;
        
        Assert.That(savedExpenseSheet, Is.Not.Null);
        Assert.That(savedExpenseSheet.Id, 
            Is.EqualTo(new Guid("4048A482-1CBA-45AA-8709-6409B9FD32E3")));
        Assert.That(savedExpenseSheet.EmployeeId, 
            Is.EqualTo(new Guid("680D0C0A-E445-4344-B67A-363589E2746A")));
        Assert.That(savedExpenseSheet.SubmissionDate, 
            Is.EqualTo(new DateTime(2018, 11, 11)));
    }

    [Observation]
    public void Then_the_operation_should_succeed()
    {
        Assert.That(_result.IsSuccessful);
    }

    private SpyExpenseSheetRepository _spyExpenseSheetRepository;
    private CreateExpenseSheetHandler _sut;
    private Result _result;
}

```

The test scenario verifies the happy path of the Subject Under Test. When creating an instance of the _CreateExpenseSheetHandler_ class, we pass an instance of the _StubEmployeeRepository_ for providing an _Employee_ as an indirect input and an instance of the _SpyExpenseSheetRepository_ that we just saw. The first observation we make uses the _SavedExpenseSheet_ property of the _SpyExpenseSheetRepository_ in order to verify whether the saved _ExpenseSheet_ object contains the information that we specified through the command. The second observation merely verifies whether the return value of the _Handle_ method indicates a successful outcome.

A _Spy_ acts as an observation point for the indirect outputs of the Subject Under Test. It functions as a hatch for verifying these outputs by unit tests. It doesn’t do any verifications of its own in contrast to the next type of test double.

#### Mock

The fourth type of test double is called a _Mock_. A _Mock_ does the exact same things as a _Spy_, only it’s more intelligent than a _Spy_ and it knows what should happen regarding the indirect outputs of the Subject Under Test. A _Mock_ returns values for the query methods of its public interface. It also captures the interactions with the command methods of its public interface. But it also provides the ability for a unit test to state its expectations, and after exercising the Subject Under Test, provides the ability to instruct the _Mock_ to verify the outcome according to these expectations.

Let’s have a look at an example of a _Mock_.

```csharp
public class MockExpenseSheetRepository : IExpenseSheetRepository
{
    private readonly ExpenseSheet _result;
    private ExpenseSheet _expectedExpenseSheetToBeSaved;
    private ExpenseSheet _savedExpenseSheet;
    
    public MockExpenseSheetRepository(ExpenseSheet result)
    {
        _result = result;
    }
    
    public ExpenseSheet Get(Guid id)
    {
        return _result;
    }

    public void Save(ExpenseSheet expenseSheet)
    {
        _savedExpenseSheet = expenseSheet;
    }

    public void ExpectSaveToBeCalled(ExpenseSheet expenseSheetToBeSaved)
    {
        _expectedExpenseSheetToBeSaved = expenseSheetToBeSaved;
    }
    
    public void Verify()
    {
        if(null == _expectedExpenseSheetToBeSaved)
            return;
        
        Assert.That(_savedExpenseSheet, Is.Not.Null);
        Assert.That(_savedExpenseSheet.Id, 
            Is.EqualTo(_expectedExpenseSheetToBeSaved.Id));
        Assert.That(_savedExpenseSheet.EmployeeId, 
            Is.EqualTo(_expectedExpenseSheetToBeSaved.EmployeeId));
        Assert.That(_savedExpenseSheet.SubmissionDate, 
            Is.EqualTo(_expectedExpenseSheetToBeSaved.SubmissionDate));
    }
}

```

The _MockExpenseSheetRepository_ class implements the _IExpenseSheetRepository_ interface. The constructor of the mock expects an instance of an _ExpenseSheet_ that can be returned by the _Get_ method when and if called. It also assigns the _ExpenseSheet_ object that is specified to the _Save_ method in the _\_savedExpenseSheet_ member variable. Notice that there are two additional methods compared to the implementation of the spy that we’ve seen earlier. One is the _ExpectSaveToBeCalled_ method which simply stores a specified _ExpenseSheet_ object in the _\_expectedExpenseSheetToBeSaved_ member variable. The other one is the _Verify_ method. It first checks whether the _\_expectedExpenseSheetToBeSaved_ member variable has been set. If not, then there’s nothing to verify. Otherwise, the _ExpenseSheet_ object that is stored through the _Save_ method is verified and compared against the expected _ExpenseSheet_ object.

```csharp
[Specification]
public class When_creating_a_new_expense_sheet__mock_example
{
    [Establish]
    public void Context()
    {
        var employee = Example.Employee().WithId(new Guid("680D0C0A-E445-4344-B67A-363589E2746A"));
        var stubEmployeeRepository = new StubEmployeeRepository(employee);

        var expenseSheetToBeSaved = Example.ExpenseSheet()
            .WithId(new Guid("4048A482-1CBA-45AA-8709-6409B9FD32E3"))
            .WithEmployee(employee)
            .WithSubmissionDate(new DateTime(2018, 11, 11));
            
        _mockExpenseSheetRepository = new MockExpenseSheetRepository(null);
        _mockExpenseSheetRepository.ExpectSaveToBeCalled(expenseSheetToBeSaved);
        
        _sut = new CreateExpenseSheetHandler(stubEmployeeRepository, _mockExpenseSheetRepository);
    }

    [Because]
    public void Of()
    {
        var command = new CreateExpenseSheet(
            new Guid("4048A482-1CBA-45AA-8709-6409B9FD32E3"), 
            new Guid("680D0C0A-E445-4344-B67A-363589E2746A"), 
            new DateTime(2018, 11, 11));

        _result = _sut.Handle(command);
    }
    
    [Observation]
    public void Then_the_approved_expense_sheet_should_be_saved()
    {
        _mockExpenseSheetRepository.Verify();
    }

    [Observation]
    public void Then_the_operation_should_succeed()
    {
        Assert.That(_result.IsSuccessful);
    }

    private MockExpenseSheetRepository _mockExpenseSheetRepository;
    private CreateExpenseSheetHandler _sut;
    private Result _result;
}

```

The test scenario also verifies the happy path of the Subject Under Test. Instead of a _Spy_ we now create an instance of the _CreateExpenseSheetHandler_ class using the _MockExpenseSheetRepository_ that we just saw. The mock is instructed to expect a call to the _Save_ method with a specific _ExpenseSheet_ object containing the data that we expect. The observation that verifies whether a new _ExpenseSheet_ object is saved by the _CreateExpenseSheetHandler_ simply calls the _Verify_ method on the mock. If things don’t work out as expected, then the _MockExpenseSheetRepository_ will fail the test on its behalf.

There are generally two different types of mocks: strict and non-strict mock objects. Strict mocks expect that recorded calls are performed in a particular order. On the contrary, non-strict mocks don’t impose this restriction. The general guideline and best practice is to avoid strict mocks as much as possible. Unit tests that make use of strict mocks impose even more constraints on the implementation and are therefore more strongly coupled to the concrete implementation of the Subject Under Test. Therefore mock objects should almost always be non-strict.

So now we’ve seen the four different flavours of test doubles that are important for **solitary** tests. There’s one more type of test double that we’re going to briefly discuss now for the sake of completeness.

#### Fake

A different kind of test double compared to the other types of test doubles that we’ve seen so far is called a _Fake_. A _Fake_ is an object that, from an outside view, simulates the exact same functionality and behaviour as the real implementation that it replaces. The difference with the other types of test doubles exists in the fact that a _Fake_ is not controlled or observed by a test.

Let’s have a look at an example of a _Fake_.

```csharp
public class FakeExpenseSheetRepository : IExpenseSheetRepository
{
    private readonly Dictionary<Guid, ExpenseSheet> _expenseSheets;
    
    public FakeExpenseSheetRepository()
    {
        _expenseSheets = new Dictionary<Guid, ExpenseSheet>();
    }
    
    public ExpenseSheet Get(Guid id)
    {
        var isFound = _expenseSheets.TryGetValue(id, out var expenseSheet);
        return isFound ? expenseSheet : null;
    }

    public void Save(ExpenseSheet expenseSheet)
    {
        var current = Get(expenseSheet.Id);
        var currentVersion = current?.Version ?? 0;
        
        if(currentVersion != expenseSheet.Version)
            throw new OptimisticConcurrencyException<ExpenseSheet>(expenseSheet.Id, currentVersion, 
                expenseSheet.Version);

        expenseSheet.Version += 1;
        _expenseSheets[expenseSheet.Id] = expenseSheet;
    }
}

```

The _FakeExpenseSheetRepository_ class provides a fully functional implementation of an _ExpenseSheetRepository_, including code for enforcing optimistic concurrency. The only difference with the real implementation is that the _FakeExpenseSheetRepository_ doesn’t access a data store. Instead it uses a _Dictionary_ to store _ExpenseSheet_ objects in memory.

```csharp
[Specification]
public class When_creating_a_new_expense_sheet__fake_example
{
    [Establish]
    public void Context()
    {
        var employee = Example.Employee().WithId(new Guid("680D0C0A-E445-4344-B67A-363589E2746A"));
        var stubEmployeeRepository = new StubEmployeeRepository(employee);
            
        _fakeExpenseSheetRepository = new FakeExpenseSheetRepository();            
        _sut = new CreateExpenseSheetHandler(stubEmployeeRepository, _fakeExpenseSheetRepository);
    }

    [Because]
    public void Of()
    {
        var command = new CreateExpenseSheet(
            new Guid("4048A482-1CBA-45AA-8709-6409B9FD32E3"), 
            new Guid("680D0C0A-E445-4344-B67A-363589E2746A"), 
            new DateTime(2018, 11, 11));

        _result = _sut.Handle(command);
    }

    [Observation]
    public void Then_the_operation_should_succeed()
    {
        Assert.That(_result.IsSuccessful);
    }

    private FakeExpenseSheetRepository _fakeExpenseSheetRepository;
    private CreateExpenseSheetHandler _sut;
    private Result _result;
}

```

The test scenario now uses the _FakeExpenseSheetRepository_ instead of a spy or a mock. Because the test fixture uses a fake, we are no longer able to verify whether a new _ExpenseSheet_ object is saved in the repository. The only thing that we can do is verify whether the return value of the _Handle_ method indicates a successful outcome.

One might argue that using fakes no longer have anything to do with behaviour verification. That’s indeed a statement that has a certain truth to it. They’re used by tests for reasons other than verification of indirect outputs. Generally speaking, _Fake_ objects are not well suited for solitary tests. So I usually try to avoid them for solitary tests when possible.

On the other hand, _Fake_ objects are more than useful for sociable tests. But caution is still advisable when using them on a large scale though. A fake implementation needs to be kept in sync with the real implementation at all times.

One way to accomplish this is to use _Contract Tests_. Contract tests not only verify the outside observable behaviour of out-of-process services like databases, web services, etc. … . They also run against the fake implementation to ensure 100% behavioural compatibility. This can involve some significant development effort. So carefully consider when and where to use this powerful technique.

#### Summary

![Visualisation of indirect inputs](https://dev-to-uploads.s3.amazonaws.com/i/frxopzgylfbga1k89xpu.png)

This diagram provides an overview of the different types of test doubles and for which kinds of tests they are most often applicable. Learning about the behaviour of each type of test double is essential to understanding the differentlevels of coupling that they impose. More on that in a next blog post.