No hace mucho tuve una pregunta similar cuando estaba refactorizando algunas de mis propias pruebas, y hay un par de formas de hacerlo:
a) Proporcione un tipo exportado y un Open
o Connect
función que lo devuelve - por ejemplo,
type DB struct {
db *sql.DB
}
// Using http://jmoiron.github.io/sqlx/ for this example, but
// it has the same interface as database/sql
func Open(opts *Options) (*DB, error) {
db, err := sqlx.Connect(opts.Driver, fmt.Sprintf("host=%s user=%s dbname=%s sslmode=%s", opts.Host, opts.User, opts.Name, opts.SSL))
if err != nil {
return nil, err
}
return &DB{db}, nil
}
... y luego cada uno de tus pruebas, escribir funciones de configuración y desmontaje que devuelven una instancia de *DB
en las que define las funciones de su base de datos (como métodos, es decir, func (db *DB) GetUser(user *User) (bool, error)
):
// Setup the test environment.
func setup() (*DB, error) {
err := withTestDB()
if err != nil {
return nil, err
}
// testOptions is a global in this case, but you could easily
// create one per-test
db, err := Open(testOptions)
if err != nil {
return nil, err
}
// Loads our test schema
db.MustLoad()
return db, nil
}
// Create our test database.
func withTestDB() error {
db, err := open()
if err != nil {
return err
}
defer db.Close()
_, err = db.Exec(fmt.Sprintf("CREATE DATABASE %s;", testOptions.Name))
if err != nil {
return err
}
return nil
}
Tenga en cuenta que esto es una especie de prueba de "integración", pero prefiero probar con una base de datos "real", ya que burlarse de la interfaz no lo ayudará a detectar problemas con sus consultas/sintaxis de consultas.
b) La alternativa, aunque menos extensible en el lado de la aplicación, es tener un db *sql.DB
global variable que inicializas en init()
dentro de sus pruebas, dado que las pruebas no tienen un orden garantizado, deberá usar init()
—y luego ejecute sus pruebas desde allí. es decir,
var db *sql.DB
func init() {
var err error
// Note the = and *not* the assignment - we don't want to shadow our global
db, err = sqlx.Connect(...)
if err != nil {
...
}
err := db.loadTestSchema
// etc.
}
func TestGetUser(t *testing.T) {
user := User{}
exists, err := db.GetUser(user)
...
}
Puede encontrar algunos ejemplos prácticos en repo de GitHub de drone.io , y también recomendaría este artículo sobre la estructuración de aplicaciones Go (especialmente las cosas de DB).