Outro dia escrevi testes para um módulo que interage com um banco de dados. Eu não queria vincular o módulo de teste a esse banco de dados - isso cria requisitos adicionais para o ambiente em que o teste será realizado. Eu também não queria criar instâncias do tipo sql.Rows com as chapas necessárias de uma só vez - para mim esse tipo é uma "caixa preta" e gostaria que permanecesse dessa maneira. A pesquisa no tópico também não encontrou nada de interessante.
Eu queria compartilhar minha descoberta com a comunidade: na distribuição principal do Go, existe uma ferramenta quase pronta para essas necessidades: chamada FakeDb.
O que essa ferramenta pode fazer?
Na verdade, é o objeto de banco de dados mais simples, mas completo, um banco de dados que pode criar tabelas, preenchê-las e fazer amostras simples a partir delas. Todas as tabelas criadas são temporárias e existem enquanto existir a instância FakeDb. Além disso, a emulação de atraso ao chamar um comando e a exceção de emulação estão disponíveis.
Comandos do FakeDb
Os comandos consistem em frases separadas por uma barra vertical - |. Uma frase é uma palavra-chave ou uma expressão no formato "chave = valor". Onde chave é o nome da coluna.
Limpe
O comando destrói as tabelas e retorna um resultado vazio. Além disso, verifica-se que não há conflito.
Exemplo de chamada:
WIPE
CRIAR
O comando cria uma tabela com as colunas especificadas do tipo especificado.
Formato da chamada:
CREATE|_|1=,...,N=
Tipos suportados:
- bool
- nullbool - booleano ou nulo
- int32
- corda
- nullstring - string ou NULL
- int64
- nullint64 - int64 ou NULL
- float64
- nullfloat64 - float64 ou NULL
- data e hora
- any - interface vazia, ou seja, qualquer tipo
Exemplo de chamada:
CREATE|people|name=string,age=int32,photo=any,dead=bool,bdate=datetime
INSERIR
O comando adiciona linhas à tabela criada.
Formato da chamada:
INSERT|_|1=,...,N
A seguir, o valor pode ser definido de três maneiras:
- Especifique explicitamente um valor, por exemplo
123
. - Indique "?" E passe o valor como parâmetro.
- Especifique "? Parameter_name" e passe o valor para o parâmetro nomeado.
Exemplo de chamada:
INSERT|people|name=Alice,age=?,photo=?photo
SELECT
O comando permite selecionar todas as linhas da tabela ou com alguma seleção.
Formato da chamada:
SELECT|_|1,...,N| SELECT|_|1,...,N|1=?,...,M
Exemplo de chamada:
SELECT|categories|category_id,category_parent_id,category_name| SELECT|categories|category_id,category_parent_id,category_name|category_parent_id=?parent
O resultado é uma instância completa do sql.Rows.
WAIT
Simula um atraso na execução de um comando. Deve ser adicionado antes de qualquer um dos comandos acima.
Formato da chamada:
WAIT||
O atraso é indicado como a quantidade e o postfix que indicam a unidade de medida: s - segundos, n - nanossegundos, u - microssegundos, h - horas e assim por diante (a função time.ParseDuration () é usada).
Exemplo de chamada:
WAIT|1s|SELECT|categories|category_id,category_parent_id,category_name|
Pânico
Lança uma exceção ao chamar um comando.
Formato da chamada:
PANIC|_|
O valor de MethodName será colocado no campo stmt.panic
(digite fakeStmt).
Exemplo de chamada:
PANIC|blablabla|SELECT|categories|category_id,category_parent_id,category_name|
Use
O FakeDb foi criado para testar o pacote "sql" da entrega principal como um script de teste . Não o encontrei em um pacote separado. Portanto, eu mesmo o selecionei em um pacote e o coloquei aqui: gihub .
Foram necessárias edições menores para destacar o pacote.
Exemplo de uso
package packname import ( "fmt" "testing" "io/ioutil" "database/sql" "github.com/a1div0/fakedb" ) func TestFoo(t *testing.T) { fc := &fakedb.FakeConnector{ } db := sql.OpenDB(fc) if db.Driver() != fakedb.Fdriver { t.Error("OpenDB should return the driver of the Connector") return } if _, err := db.Exec("WIPE"); err != nil { t.Error("exec wipe: %v", err) } defer db.Close() db.Exec("CREATE|users|user_email=string,user_id=int64") db.Exec("INSERT|users|user_email=?,user_id=?", "test@email.com", 345) rows, err := db.Query( "SELECT|users|user_id|user_email=?email", sql.Named("email", user_email), ) if err != nil { t.Error(err) } result, err := Foo(rows)
Obrigado pela atenção.
PS: Por favor, escreva nos comentários - você usa emulação de banco de dados nos testes? Em caso afirmativo, qual pacote?