In Go, mocking a function that is declared on a concrete type, like func F() {} and func (T) M() {}, is not possible. However, there are other approaches to achieve similar functionality.
Go allows for mocking function values, regardless of whether they are stored in variables, as fields on a struct, or as parameters passed to other functions. For instance, consider the following:
var Fn = func() { ... } type S struct { Fn func() } func F(Fn func())
In all three cases, Fn is mockable.
A more preferred approach to mocking in Go is to use interfaces. For example:
type ProductRepository interface { GetProductById(DB *sql.DB, ID int) (p Product, err error) } // The real implementer type ProductStore struct{} func (ProductStore) GetProductById(DB *sql.DB, ID int) (p Product, err error) { q := "SELECT * FROM product WHERE id = ?" // ... } // The mock implementer type ProductRepositoryMock struct{} func (ProductRepositoryMock) GetProductById(DB *sql.DB, ID int) (p Product, err error) { // ... }
Any code that relies on ProductRepository can now use ProductStore in normal scenarios and ProductRepositoryMock during testing.
Another option for mocking that allows for preserving your existing function declarations is to define an interface that mimics the methods of *sql.DB and use it instead. For instance:
type DBIface interface { Query(query string, args ...interface{}) (*sql.Rows, error) // Only declare methods that are actually used. } type DBMock struct{} func (DBMock) Query(query string, args ...interface{}) (*sql.Rows, error) { // ... } func GetProductByName(DB DBIface, name string) (p Product, err error) { ... }
With this approach, the DB parameter to GetProductByName becomes mockable.
The above is the detailed content of How Can I Effectively Mock Functions in Go?. For more information, please follow other related articles on the PHP Chinese website!