avevo una domanda simile non molto tempo fa, quando il refactoring alcuni dei miei propri test, e ci sono un paio di modi per farlo:
a) Fornire un tipo esportato e un Open
o Connect
funzione che restituisce - per esempio
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
}
... e poi ciascuno dei vostri test, scrivere configurazione & funzioni teardown che restituiscono un'istanza di *DB
che si definiscono le funzioni di database su (come metodi - vale a dire 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
}
Si noti che questo è un po 'test di "integrazione", ma io preferisco fortemente testare un database "reale" dal momento che il mocking dell'interfaccia non ti aiuterà a cogliere problemi con le tue query/sintassi delle query.
b) L'alternativa, anche se meno estensibili sul lato applicazione, è di avere un db *sql.DB
variabile globale che si inizializza in init()
entro i test-test dal momento che non hanno alcun ordine garantito è necessario utilizzare init()
-e quindi eseguire i tuoi test da lì. vale a dire
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)
...
}
Potete trovare alcuni esempi pratici in drone.io's GitHub repo, e mi piacerebbe anche consigliare this article on structuring Go applications (specialmente la roba DB).
Penso che sia necessario prendere in giro il livello di accesso ai dati. – RoninDev
Questo è quello che ho fatto alla fine - https://github.com/sumitasok/go-test-db. Per favore, dammi i tuoi pensieri ob questo. Aggiungerò presto un Readme. –
C'è https://github.com/DATA-DOG/go-sqlmock solo per quello, che è il driver sql e simula completamente un database senza una vera connessione. – Gediminas