sql >> Base de Datos >  >> RDS >> Mysql

Desarrollo basado en pruebas para verificar los métodos involucrados en las consultas de la base de datos

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