Unit testing sql.DB/Tx calls in Go with gomock

115 Views Asked by At

It’s already the 3rd day I’m thinking about this problem but without any solution. I need to unit test my Tx manager - check that in all combinations rollback() and commit() methods all called in proper sequence.

sql.DB has the method BeginTx which returns sql.Tx. It returns a final type, not an interface (according to Go - pass interfaces and return types). But in this case it’s not possible to return mock from BeginTx call - because even if we return mocked Tx-interface it has a different type!

I tested it in some hacky way - I just changed sql.DB mock to return Tx interface instead of final type, and tested against it, but now it needs to integrate test into production code.

I don’t want to make some wrappers on sql.DB in production code just to make unit tests working, but what are other solutions???

And why is it a standard in Go to return types instead of interfaces?
It makes testing harder!

1

There are 1 best solutions below

4
samsmi7h On

Dependency injection is the way to go.

sql.BeginTx returns a concrete type, but everywhere you pass the transaction, you should depend on a transaction interface rather than the type.

e.g.

type Transaction interface {
    Commit() error
    Exec(query string, args ...any) (sql.Result, error)
}

Now you can inject a mock transaction rather than the real sql.Tx anywhere as long as your mock satisfies the same type. For testing, your mock could then record calls to the transaction which you can verify.