Mysql
 sql >> Base de Dados >  >> RDS >> Mysql

Desenvolvimento orientado a testes para verificar os métodos envolvidos nas consultas ao banco de dados


Eu tive uma pergunta semelhante há pouco tempo ao refatorar alguns dos meus próprios testes, e há algumas maneiras de fazer isso:

a) Forneça um tipo exportado e um Open ou Connect função que o retorna - por exemplo
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 então cada um de seus testes, escrever funções de configuração e desmontagem que retornam uma instância de *DB em que você define suas funções de banco de dados (como métodos - ou seja, 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
}

Observe que isso é um teste de "integração", mas prefiro testar em um banco de dados "real", pois zombar da interface não ajudará você a detectar problemas com suas consultas/sintaxe de consulta.

b) A alternativa, embora menos extensível no lado da aplicação, é ter um db *sql.DB global variável que você inicializa em init() dentro de seus testes - como os testes não têm ordem garantida, você precisará usar init() — e, em seguida, execute seus testes a partir daí. ou seja
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)
   ...
}

Você pode encontrar alguns exemplos práticos no drone.io's GitHub repo , e também recomendo este artigo sobre como estruturar aplicativos Go (especialmente as coisas do DB).