{{ .WebDevStation }}
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.
In this post, I’m going to show the way how we can implement a simple queue in Golang, using channels.
go queue channel goroutineIn this article I’m going to show how easy we can sort strings alphabetically in different languages, using Go. It seems like an easy task if we want to sort English words, however, it’s not so trivial if we want to sort correctly strings with special characters or in other languages, i.e Cyrillic based.
go sorting alphabetical sortIn this post I’m going to describe how can we limit user access to the specific url in golang web application. I will use chi router - a lightweight, idiomatic and composable router for building Go HTTP services.
go router chiLet’s imagine a situation when you want to alter the result, returned by some http handler to the client. Fortunately, Golang provides an easy mechanism for that, called a middleware. I’m going to dive directly to the source code, to save your time.
go middleware