Mysql
 sql >> Database >  >> RDS >> Mysql

Sviluppo guidato da test per verificare i metodi coinvolti nelle query del database

Ho avuto una domanda simile non molto tempo fa durante il refactoring di alcuni dei miei test e ci sono un paio di modi in cui puoi farlo:

a) Fornire un tipo esportato e un Open o Connect funzione che lo restituisce, ad es.

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 tuoi test, scrittura di funzioni di configurazione e smontaggio che restituiscono un'istanza di *DB su cui definisci le funzioni del tuo database (come metodi - cioè 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
}

Nota che questo è in qualche modo un test di "integrazione", ma preferisco fortemente testare su un database "reale" poiché deridere l'interfaccia non ti aiuterà a rilevare problemi con le tue query/sintassi di query.

b) L'alternativa, sebbene meno estensibile lato applicazione, è avere un db *sql.DB globale variabile inizializzata in init() all'interno dei tuoi test:poiché i test non hanno un ordine garantito, dovrai utilizzare init() —e poi esegui i tuoi test da lì. cioè

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

Puoi trovare alcuni esempi pratici in repo GitHub di drone.io , e consiglierei anche questo articolo sulla strutturazione delle applicazioni Go (soprattutto le cose DB).