Database Mocking in Go

Konstantin Makarov
Scum-Gazeta
Published in
3 min readDec 1, 2020

Today we’ll talk about unit testing.
Namely, about testing our repository — working with a database.
The indicator of a good and clean application are beautifully and clearly written tests, with almost complete coverage of this service.
Let’s do what we can do well with you — write a web application :)

But first we will talk a little about the architecture of our application.

Application architecture

Our architecture will be close to perfect and will consist of several layers.

  • Middlewares
  • Endpoint layer
  • Business layer
  • Repository layer (today we are here)

Middlewares

Here we will log and authorize incoming requests.
From here there will be errors like: 401, 403.

Endpoints

Here we will accept user HTTP-requests,
deseralize them into our go-structure and call our service methods with this data.
Errors such as 400 will be generated here.

Business logic

There will be our application logic, which we will change from service to service, changing the behavior of the application.
Usually, if your team uses code generation services,
then this is exactly the service that will need to be “revived” manually. Errors of this level will be: 404, 409, 422

Repository

And this is exactly what we are going to do now :) The layer that implements the work with your repository.
Most likely a database. From this Mariana Trench already 500 serious errors will appear.

Testing the repository

According to the testing pyramid, we need unit tests to cover almost everything and to execute them as quickly as possible.
To achieve this, we abandon the use of a real database, and replace it with mock.
For this we will use the popular SQLMock library.

By the way, the developer of this wonderful library is looking for a maintainer and after reading this article you have every chance of becoming one :)

Let’s see how it works from the inside:

As you know, the SQL-driver standard library allows you to register any driver. In your code, this is exactly the import that you constantly forget about :)

_ “github.com/go-sql-driver/mysql

in the library it looks like this (registering a new sqlMock driver):

And now instead of interacting with a real database, we will interact with the following object:

Now let’s see how we start our testing:

Here we are interested in the first two, returned parameters db and mock.

We will use the first one instead of connecting in our repository.
It returns a pointer to the standard *sql.DB, so you can use it wherever you are using your real database connection.
In our case, this will be the essence of the mock library, which will implement standard SQL-driver methods. Only these methods will not contact our database, they will simply remember the sequence of your actions.

With the second object, we will set our expectations. Fill in the expected [] expectation array.
Roughly speaking, we will add our SQL query to the expectation array. Why an array? Well, because we may have a whole definite sequence of actions (remember transactions).

Here we will also indicate whether our SQL query should return an error or just successfully complete.

This is a normal query, for example: Update, Delete ..

Mock execute query

Here we perform a request for certain data.

Mock data select

We indicate the regularity of the request that we expect. We specify what data the request should return and if it should succeed or return some specific error (for ex. sql.NoRows)

In the data, we indicate which columns are present in the request and the data that we will return for them. We can return a few lines or not return anything.

Well, that’s the principle and that’s it. We have a contract, let’s try to execute it:

Inside we simply check the executed SQL query against the regex we described above. Further, the request returns the data that we specified or there may be an error. We can already check this in our test-cases.
This is basically all we need to know to write simple test scripts with a separate database.

There are some other useful features in the library, which I recommend that you familiarize yourself with as your homework :)

See the official examples of this library usage. You will find there is everything you need.
https://github.com/DATA-DOG/go-sqlmock/tree/master/examples

Happy testing!

--

--