Modular Interface Mocks for Testing

By January 24, 2018 February 1st, 2018 clypd Blog, Engineering, Technology

It’s been almost three and a half years since I published “Database Testing Patterns in Go“. The post was about how at clypd we were using dependency injection to test functions that would access external data sources. It’s a testament to the effectiveness of the pattern that it lasted so long. However, as our code base has grown over these years, we eventually started to run into some growing pains associated with the way we were doing things.

Summary of “Database Testing Patterns in Go”

To recap, we have an interface:

We have an implementation:

And a mock to inject for testing:

Growing Pains

This is simple enough, but this only lets us test a very small subset of the paths the application can take. One notable attribute left unmentioned is error handling. Database connections are external resources, and things can go wrong with the connection or with our calls to it. We might wish to test that the error paths act as we expect them to. Let’s expand the definition:

While this does the job, the pattern doesn’t scale in a variety of ways. It starts to bloat quickly when adding more and more data accessors onto the definition and it’s easy to run into naming problems. As more clients are created for the database access functions, we end up with more of these custom mocks littered all over the code base and many redundant definitions.

As an example, if we had another function that processed something differently, say into otherResultType, then we have to repeat the whole mock definition above with only the final method changing. If we have several of these these, and then modify GetIDs() to take in parameterized queries in order to support one of the three use cases, then all of them have to change.

Objectives of a Replacement Pattern

The process is clearly unsustainable, so it was only a matter of time until it became obvious that we needed a new pattern. So, we set out to create one with two major goals in mind.

First, we wanted to retain the narrow scope of the individual implementations. Test code often serves a documentation purpose. From looking at the mock implementation, I can get a sense of the data that a function is accessing. One profound weakness with Go’s interfaces (as of 1.9) is that one can’t add the same method from two component interfaces i.e.

As a result, we tend to use one interface definition at a high level and rely on the mocks to convey what was happening on the lower levels. Using a large mock would remove this information.

Secondly, and seemingly contrary to the former, we wanted mocks to be reusable. Many of the problems were created by a proliferation of one-off mocks. We should be able to build them out of components in keeping with the principles of DRY, and crucially, this shouldn’t increase the complexity of the tests.

In Go, the way to share functionality (akin to inheritance in other languages) is via embedding. It allows us to access the methods of the inner struct, getting rid of bookkeeping, and repetition in the mock definition. Embedding leaves us with the problem of making sure that we don’t embed the same method twice.


To get around this problem with embedding, we needed to change the way we thought about mocks. Mocks had always been associated with a particular use case, for example, how the MockDB type above corresponds to the function in the previous post, and the value of this association is evidenced by our desire to retain their narrow scope. With embedding, the mock itself still retains these features. On the other hand, the components do not need these features, and are in fact better off without them. So instead of grouping components together around any one of a number of different taxonomies, we decided that all the components would be free standing.

From the above example, the result looks like this:

The use cases then look like this:

A mock that commits a different type of result is as simple as this:

The database is a monolithic piece of functionality. This is a good thing as it’s burdensome to instantiate a type for every query we want to run. However, for the mock we want to instantiate a type for every query we want to run because we need to fill in the canned response. This means we can use the opposite of the pattern used for databases (via embedding), and the interface means that the client code can’t tell the difference.

This is not possible with a inheritance approach, so it’s not something those who come from object-oriented backgrounds are trained to look for. It only works because of the trait-like function of embedding to promote the method to the outer type.


To date, we’ve been very happy with this approach. We don’t have to repeat ourselves and the tests are clearer, thanks to a consistent naming scheme for the various fields. There is no longer a proliferation of inconsistent mocks and most times when the database accessor’s signature changes there’s only one place that needs updating. We’ve moved all of the mocks for database access to a package humorously called mocksoup after Lewis Carroll’s mock turtle soup, which has led to no end of soup metaphors (the components are called “ingredients”) and puns.

There are also some future improvements we’d like to make. Writing these “ingredients” is largely tedious and samey and could benefit from code generation. We’ve historically not done too good a job at parameter checking because they tended to make an already confusing interface worse. Now that the interface is simple, we’d like to add to it the capability to check that we’re constructing parameters correctly. These were problems we had before, but we’re now in a much better place to do something about it.

Leave a Reply