Blog

Excessive Specification of Test Doubles

May 20, 2020

Previously we’ve discussed the different kinds of test doubles. By using test doubles in our solitary tests, we also introduce more coupling between the test code and the implementation. However, the good news is that there are also some things we can do in order to somewhat reduce this coupling.

A very important item of caution is to avoid excessive specification of method behaviour. Let’s have a look at an example.

var approverId = new Guid("224FE5B8-EDBB-4F8B-8654-715C1C294CFD");
HeadOfDepartment headOfDepartment = Example.HeadOfDepartment().WithId(approverId);

var approverRepositoryMock = Substitute.For<IApproverRepository>();
approverRepositoryMock.Received().Get(approverId).Returns(headOfDepartment);

Here we create a mock for the IApproverRepository interface, created by the NSubstitute framework. When the subject under test makes a call to the Get method using a specific identifier, then an instance of the HeadOfDepartment is returned. However, that’s not the only thing that happens. The mock also verifies whether the subject under test actually makes a call to the Get method. If not, then the test will fail. The approach taken in this example illustrates the concept of excessive specification.

With behaviour verification, the degree of coupling between the test code and the implementation depends on the type of test double being used. Using a Dummy or a Stub results in the least amount of coupling, while using a Spy or a Mock induces the highest amount of coupling.

For indirect inputs, as is the case in our example, we should avoid using mocks at all times. We should use stubs instead. Let’s have a look at an improved version of the previous example.

HeadOfDepartment headOfDepartment = Example.HeadOfDepartment()
    .WithId(new Guid("224FE5B8-EDBB-4F8B-8654-715C1C294CFD"));

var approverRepositoryStub = Substitute.For<IApproverRepository>();
approverRepositoryStub.Get(Guid.Empty).ReturnsForAnyArgs(headOfDepartment);

Here we no longer verify whether the Get method is being called. We only state that whenever the Get method of the ApproverRepository is called, no matter what the identifier might be, just return the specified HeadOfDepartment object. So we basically switched from using a mock to using a stub.

For solitary tests that make use of test doubles, prefer the use of stubs over spies and mocks. Generalisation of stub method arguments make solitary tests more resilient to changes. I always try to use the most generic argument matcher that is feasible for a particular scenario.

Obviously, we sometimes need to use spies or mocks. For those cases, it’s very important to restrict their use to only verifying indirect outputs. We should only specify what should happen and nothing more.

The following piece of test code is an example where the use of a mock is warranted.

[Observation]
public void Then_the_approved_expense_sheet_should_be_saved()
{
    _expenseSheetRepositoryMock.Received().Save(_expenseSheet);
}

When observing solitary tests that make use of test doubles in a decent code base, you might see that the usage ratio of dummies and/or stubs is significantly higher than that of spies and/or mocks. This should give us a decent idea about the usage of the different types of test doubles.

If you and your team want to learn more about how to write maintainable unit tests and get the most out of TDD practices, make sure to have look at our trainings and workshops or checkout the books section. Feel free to reach out at infonull@nullprincipal-itnull.be.

Profile picture of Jan Van Ryswyck

Jan Van Ryswyck

Thank you for visiting my blog. I’m a professional software developer since Y2K. A blogger since Y2K+5. Provider of training and coaching in XP practices. Curator of the Awesome Talks list. Past organizer of the European Virtual ALT.NET meetings. Thinking and learning about all kinds of technologies since forever.

Comments

About

Thank you for visiting my website. I’m a professional software developer since Y2K. A blogger since Y2K+5. Author of written words. Provider of training and coaching in XP practices. Curator of the Awesome Talks list. Past organizer of the European Virtual ALT.NET meetings. Thinking and learning about all kinds of technologies since forever.

Contact information

(+32) 496 38 00 82

infonull@nullprincipal-itnull.be