A copy-paste go SQL mock for GORM

When it comes to writing robust and reliable tests for your Go applications, having a well-structured and efficient testing setup is crucial. One common challenge in testing Go applications is dealing with database interactions. To ensure that your code functions correctly, it’s essential to create a controlled environment for database operations during testing. In this blog post, we’ll explore how to create a mock GORM database for testing purposes, allowing you to isolate and verify your database interactions in a controlled manner.

Here is some copy-and-paste code (explained below) which should get you started.

import (
	"github.com/DATA-DOG/go-sqlmock"
	"gorm.io/gorm"
	"gorm.io/gorm/logger"
)

func NewMockGORM() (GORM *gorm.DB, close func()) {
	db, mock, err := sqlmock.New()
	if err != nil {
		panic(err)
	}

	// GORM always runs this query, so mock it for all tests
	mock.ExpectQuery("SELECT VERSION()").WillReturnRows(sqlmock.NewRows([]string{"version"}).AddRow("5.7.0"))

	GORM, err = gorm.Open(mysql.New(mysql.Config{Conn: db}), &gorm.Config{Logger: logger.Default.LogMode(logger.Silent)})
	if err != nil {
		panic(err)
	}

	return GORM, func() { db.Close() }
}Code language: PHP (php)

The code block above defines a NewMockGORM function that sets up a mock GORM database instance for testing. Let’s break down what this code does and how it can be a valuable addition to your testing toolkit.

Setting up a Mock GORM Database

Read more

Dependency injection in go using fx, and replacing services for test

I’m writing a new go application and ended up giving fx (by uber) a try for dependency injection. The getting started docs were brilliant for my use case (creating an API), but the examples for how to inject mock services for tests were lacking, so I decided to write some code examples of how I am currently using fx in tests.

General app setup

I set up my whole application in a app package, which pulls in all services that are needed.

Most of these are provided as constructor functions, with some more dynamic registration of routes as is done in the getting started docs.

package app

func New(additionalOpts ...fx.Option) *fx.App {
	return fx.New(
		fx.Provide(
			config.NewDefault,
			ses.NewSES,
			ses.NewEmailSender,
			mysql.NewGormGB,
			middleware.NewLimiterFactory,
			middleware.NewAuth,
			AsRoute(handlers.UserLogin),
			AsRoute(handlers.ListStuff),
			fx.Annotate(
				router.NewGinRouter,
				fx.ParamTags(`group:"routes"`),
			),
			server.NewHTTPServer,
		),
		fx.Invoke(func(*http.Server) {}),
		fx.Options(additionalOpts...),
	)
}Code language: Go (go)

Read more

MediaWiki CRAP – The worst of it

I don’t mean Mediawiki is crap! The Change Risk Anti-Patterns (CRAP) Index is calculated based on the cyclomatic complexity and code coverage of a unit of code. Complex code and untested code will have a higher CRAP index compared with simple well tested code. Over the last 2 years I have been tracking the CRAP index of some of Mediawikis more complex classes as reported by the automatic coverage reports, and this is a simple summary of what has been happening.

Read more