Golang Unit Testing with Gorm and Sqlmock PostgreSQL — Simplest setup

tanut aran
2 min readMar 13, 2023

--

In this tutorial I will highlight the Gorm and mock SQL part which I believe is the hard part.

There will be no unit test assert here to make it short and concise.

Simplest Gorm INSERT and test case

Here is the simple product file

package product

import (
"gorm.io/gorm"
)

type Product struct {
Code string
Price uint
}

func createProduct(db *gorm.DB) {
db.Create(&Product{Code: "D42", Price: 100})
}

Then we have the test file

package product

import (
"testing"

"github.com/DATA-DOG/go-sqlmock"
"gorm.io/driver/postgres"
"gorm.io/gorm"
)

func TestCreateProduct(t *testing.T) {
mockDb, mock, _ := sqlmock.New()
dialector := postgres.New(postgres.Config{
Conn: mockDb,
DriverName: "postgres",
})
db, _ := gorm.Open(dialector, &gorm.Config{})
createProduct(db)
}

Then we run the test

go test -cover

Got the pass result.

The key here to mock the database is sqlmock.New() this will represent the mock database and interact with Gorm.

You can extend the result to assert create success by sqlmock.ExpectExec with return value (1, 1) to asserted.

More on Querying

In more realistic case, we might need to check something before create like check the existing Code , now the mock object become more useful

package product

import (
"gorm.io/gorm"
)

type Product struct {
Code string
Price uint
}

func createProduct(db *gorm.DB) {
var product Product
err := db.First(&product, "code = ?", "D42").Error
if err != nil {
return
}
db.Create(&Product{Code: "D42", Price: 100})
}

Then our test file will add the mock.ExpectQuery

package product

import (
"testing"

"github.com/DATA-DOG/go-sqlmock"
"gorm.io/driver/postgres"
"gorm.io/gorm"
)

func TestCreateProduct(t *testing.T) {
mockDb, mock, _ := sqlmock.New()
dialector := postgres.New(postgres.Config{
Conn: mockDb,
DriverName: "postgres",
})
db, _ := gorm.Open(dialector, &gorm.Config{})

// CASE 1
createProduct(db)

// CASE 2
// fmt.Println(mock)
rows := sqlmock.NewRows([]string{"Code", "Price"}).AddRow("D43", 100)
mock.ExpectQuery(`SELECT`).WillReturnRows(rows)
createProduct(db)
}

Note the this is RegExp so I just use the SELECT statement

Also note that there is branching:

  1. If function found code = ? then it return
  2. Function run through the end and create the record

So I add two case to make the coverage become 100%

go test -cover
PASS
product coverage: 100.0% of statements
ok product 0.004s

Common mistake

testing: warning: no tests to run

You need the TestNameFunction to begin with capital letter.

Hope this help and see you next time

--

--