How to test database interactions in golang applications
22 Dec 2020

How to test database interactions in golang applications

Testing of functions with database interactions always was challenging. Recently, I found a wonderful library go-sqlmock which will simplify writing tests and mocking database queries in golang applications a lot.

And I want to share a short example of how to work with it.

First, we have to install it

go get github.com/DATA-DOG/go-sqlmock

We have this function with SQL query:

func MenuByNameAndLanguage(ctx context.Context, db *sql.DB, name string, langcode string) (*models.Menu, error) {
    result, err := db.Query("SELECT id, langcode, title, link__uri, view_sidemenu FROM menu_link_content_data WHERE menu_name=? AND langcode=?",
         name,
         langcode,
    )
    defer result.Close()
    
    var menuLinks []models.MenuLink
    for result.Next() {
         menuLink := models.MenuLink{}
         err = result.Scan(&menuLink.ID, &menuLink.Langcode, &menuLink.Title, &menuLink.URL, &menuLink.SideMenu)
         menuLinks = append(menuLinks, menuLink)    
    }
    menu := &models.Menu{
         Name: name,
         Links: menuLinks,
    }
    return menu, err
}

This function just getting menu links by menu name and language.

And now let’s test it.

We are going to test that MenuByNameAndLanguage function will return correct Menu structure.

package menu


import (
    "context"
    "testing"


    "github.com/DATA-DOG/go-sqlmock"
    "github.com/stretchr/testify/assert"
    "gitlab.mfb.io/user/graphql_server/models"
)


func TestShouldReturnCorrectMenu(t *testing.T) {

    // Creates sqlmock database connection and a mock to manage expectations.
    db, mock, err := sqlmock.New()

    if err != nil {
        t.Fatalf("an error '%s' was not expected when opening a stub database connection", err)
    }
    // Closes the database and prevents new queries from starting.
    defer db.Close()

    // Here we are creating rows in our mocked database.
    rows := sqlmock.NewRows([]string{"id", "langcode", "title", "link__uri", "view_sidemenu"}).
        AddRow(1, "en", "enTitle", "/en-link", "0").
        AddRow(2, "en", "enTitle2", "/en-link2", "0")

    // This is most important part in our test. Here, literally, we are altering SQL query from MenuByNameAndLanguage
    // function and replacing result with our expected result. 
    mock.ExpectQuery("^SELECT (.+) FROM menu_link_content_data*").
        WithArgs("main", "en").
        WillReturnRows(rows)


    ctx := context.TODO()

    // Calls MenuByNameAndLanguage with mocked database connection in arguments list. 
    menu, err := MenuByNameAndLanguage(ctx, db, "main", "en")

    // Here we just construction our expecting result.
    var menuLinks []models.MenuLink
    menuLink1 := models.MenuLink{
        ID:       1,
        Title:    "enTitle",
        Langcode: "en",
        URL:      "/en-link",
        SideMenu: "0",
    }
    menuLinks = append(menuLinks, menuLink1)

    menuLink2 := models.MenuLink{
        ID:       2,
        Title:    "enTitle2",
        Langcode: "en",
        URL:      "/en-link2",
        SideMenu: "0",
    }

    menuLinks = append(menuLinks, menuLink2)

    expectedMenu := &models.Menu{
        Name:  "main",
        Links: menuLinks,
    }
    
    // And, finally, let's check if result from MenuByNameAndLanguage equal with expected result.// Here I used Testify library (https://github.com/stretchr/testify).
    assert.Equal(t, expectedMenu, menu)
} 

As you see everything in this example was pretty straightforward.

For mo details, you can refer to GoDocs.

Related posts

Ristretto - the Most Performant Concurrent Cache Library for Go
2 Mar 2021

Ristretto - the Most Performant Concurrent Cache Library for Go

Recently, I discovered a surprisingly reliable memory caching solution, which I’m planning to use in all my further applications to increase performance. In this blog post, I will share some code examples of how you can integrate Ristretto caching library into your application.

go caching ristretto performance
An Easy Way to Load Test Your Web Apps
12 Feb 2021

An Easy Way to Load Test Your Web Apps

This time, I want to share my positive experience of load testing of one of our web services, by using K6 tool. Moreover, we will see how easily we can integrate this into the GitLab CI pipeline.

load testing k6 GitLab CI/CD testing
How to Show Flash Messages in Go web applications (with Echo framework)
4 Feb 2021

How to Show Flash Messages in Go web applications (with Echo framework)

When we create a web application, usually, there a need to communicate with the users to inform them about the results of their actions. The easiest way to communicate - is to send messages. These messages might be warnings, errors, or just informational text. In this article, we will improve the UX of our user authentication application from the previous article by adding an error flash message when the user entered a wrong password and a success message after user authorisation.

go echo flash messages
User Authentication in Go Echo with JWT
28 Jan 2021

User Authentication in Go Echo with JWT

In this article, we will build a simple user authentication functionality using JWT (JSON Web Token). In the examples, I’m going to use a Go Echo framework. This will allow us to avoid writing some boilerplate code.

go authentication JWT Echo
A Simple Queue Implementation in Golang with channels
12 Jan 2021

A Simple Queue Implementation in Golang with channels

In this post, I’m going to show the way how we can implement a simple queue in Golang, using channels.

go queue channel goroutine