Writing a custom matcher for testing with gomock

Sevcan Doğramacı
Modanisa Engineering
2 min readJan 2, 2022

Everyday we write tests for our applications. While writing a test, we usually mock integrated parts. Doing so, we aim to hide the implementation details of the integrated parts. Thanks to mocking, we do not need to modify our tests whenever there is a change in the implementation of mocked parts.

gomock is a package for mocking in go. It matches given expected values with actual ones. Sometimes, we need to customize the way it works. In this post, we will investigate such a case.

Let’s say, we have /product endpoint for inserting new products into our repository. We use a POST method handler for this.

Our handler receives requests and interacts with the service to add a new product into the repository. Below is a service test for the happy path scenario:

If you look at our test, you can see that we mock the repository and expect to call the repository’s Insert function with expectedProduct. When we run the test we face an issue:

Got: {Product - ID:000001 Description:some-description Quantity:5 CreatedAt:2022-01-02 19:58:24.594343 +0300 +03 m=+0.001580715} (*product.Product)Want: is equal to {Product - ID:000001 Description:some-description Quantity:5 CreatedAt:2022-01-02 19:58:24.594045 +0300 +03 m=+0.001282804} (*product.Product)

The issue is that the expected and actual values given to Insert function are different. Why? 🤔 After we make a deep dive, we see that the problematic part is createdAt field. There has been a subtle difference due to time.Now().

Under the hood, gomock uses some predefined matchers to work. In its official doc Matcher is defined like:

A Matcher is a representation of a class of values. It is used to represent the valid or expected arguments to a mocked method.

You can check them further here. By default, gomock matches expected values with actual ones using eqMatcher. This is where our problem on createdAt field starts.

In order to overcome this issue, we need to implement a custom matching mechanism for our Product model. gomock provides an interface for this:

If you look above, you can see that we can achieve this by implementing Matches and String methods. Here is our implementation:

In Matches function, we check if all fields are equal except for CreatedAt. Also, we implement String method to describe the fields that the matcher needs for matching.

Voila ! Now, the test is passing 🥳

To sum up, we covered how we could write a custom matcher with gomock to use a different matching strategy. That was all for this post, see u in the next episodes 🧐 🚗

References:

--

--