2014-07-18 15 views
5

Voglio creare un'applicazione basata su database utilizzando Golang. Sto cercando di farlo in modo TDD. Quando provo a testare i metodi che rendono le query Sql, quali sono tutti i pacchetti disponibili?Sviluppo guidato da test di Golang per verificare le query dei database relative ai metodi

  • Non voglio connettermi al database predefinito che utilizzo per lo sviluppo. Posso scrivere il codice per occupare un altro database di test durante l'esecuzione di un test, ma esiste una libreria go che già lo fa.

  • Esiste una libreria che esegue i test db senza connettersi al database?

Qual è il modo standard di fare test di database con golang?

+2

Penso che sia necessario prendere in giro il livello di accesso ai dati. – RoninDev

+0

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. –

+0

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

risposta

13

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).

+0

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. –

+0

BTW, la spiegazione che hai dato modo molto preciso. –

+1

Questa funzione init può essere sostituita con TestMain(), penso. – alexsmn

1

Uso una variabile globale per memorizzare l'origine dati (o stringa di connessione) del database corrente e impostare un valore diverso nella funzione di test. Dal momento che esiste un solo database che devo operare, scelgo il modo più semplice.

Problemi correlati