Alguns meses atrás, eu estava escrevendo uma aplicação. Quando fui escrever os testes do meu repositório, fiquei incomodado em ficar copiando e colando parte do código para gerar uma nova instância do repositório para cada ação do CRUD que eu queria testar. Foi então que, procurando na documentação do testify, descobri sobre o package suite.
Se você nunca utilizou o testify, recomendo que leia primeiro o nosso post “Como escrever testes com testify”.
Nesse post, vou mostrar como podemos escrever testes unitários utilizando o package testify suite e sqlmock.
Para que o post não fique muito extenso, ao invés de implementar o repositório também, vamos só imaginar que ele tem os métodos Insert, Update, Delete e FindByID implementados.
Iniciando o testify suite
Para começar, precisamos criar uma struct que faça o embed da struct suite.Suite. Esse embed é obrigatório. Todos os outros campos não são obrigatórios. São apenas uma forma de facilitar a nossa vida na hora da escrita dos testes.
type RepositorySuite struct {
suite.Suite
conn *sql.DB
DB *gorm.DB
mock sqlmock.Sqlmock
repo *repository
person *Person
}
Agora, vamos escrever o método SetupSuite. Esse método será executado antes de todos os outros. Nele, vamos adicionar os valores à todos os campos que criamos.
func (rs *RepositorySuite) SetupSuite() {
var (
err error
)
rs.conn, rs.mock, err = sqlmock.New()
assert.NoError(rs.T(), err)
dialector := postgres.New(postgres.Config{
DSN: "sqlmock_db_0",
DriverName: "postgres",
Conn: rs.conn,
PreferSimpleProtocol: true,
})
rs.DB, err = gorm.Open(dialector, &gorm.Config{})
assert.NoError(rs.T(), err)
rs.repo = NewRepository(rs.DB)
assert.IsType(rs.T(), &repository{}, rs.repo)
rs.person = &Person{ID: 1, Name: "Tiago Temporin", Age: 32, Document: "000.000.000-00"}
}
Na sequência, vamos implementar o método AfterTest. Embora não seja uma obrigatoriedade, implementando esse método, conseguimos garantir que nenhuma expectativa do sqlmock ficou sem ser atendida.
func (rs *RepositorySuite) AfterTest(_, _ string) {
assert.NoError(rs.T(), rs.mock.ExpectationsWereMet())
}
Testando o repositório
Com o setup do testify suite pronto, vamos começar escrever os testes para os métodos do repositório. Para cada método que vimos acima, iremos implementar um método de teste com o prefixo Test + o nome do método que vamos testar*****.*****
// TESTA O MÉTODO INSERT
func (rs *RepositorySuite) TestInsert() {
rs.mock.ExpectBegin()
rs.mock.ExpectExec(
regexp.QuoteMeta(`INSERT INTO "people" ("id", "name","age","document") VALUES ($1,$2,$3)`)).
WithArgs(
rs.person.ID,
rs.person.Name,
rs.person.Age,
rs.person.Document).
WillReturnResult(sqlmock.NewResult(1, 1))
rs.mock.ExpectCommit()
p, err := rs.repo.Insert(rs.person)
assert.NoError(rs.T(), err)
assert.Equal(rs.T(), rs.person, p)
}
// TESTA O MÉTODO UPDATE
func (rs *RepositorySuite) TestUpdate() {
rs.person.Age = 33
rs.mock.ExpectBegin()
rs.mock.ExpectExec(
regexp.QuoteMeta(`UPDATE "people" SET "name"=$1,"age"=$2,"document"=$3 WHERE "id" = $4`)).
WithArgs(
rs.person.Name,
rs.person.Age,
rs.person.Document,
rs.person.ID).
WillReturnResult(sqlmock.NewResult(1, 1))
rs.mock.ExpectCommit()
p, err := rs.repo.Update(rs.person)
assert.NoError(rs.T(), err)
assert.Equal(rs.T(), rs.person, p)
}
// TESTA O MÉTODO DELETE
func (rs *RepositorySuite) TestDelete() {
rs.mock.ExpectBegin()
rs.mock.ExpectExec(
regexp.QuoteMeta(`DELETE FROM "people" WHERE "people"."id" = $1`)).
WithArgs(rs.person.ID).
WillReturnResult(sqlmock.NewResult(0, 1))
rs.mock.ExpectCommit()
err := rs.repo.Delete(rs.person.ID)
assert.NoError(rs.T(), err)
}
// TESTA O MÉTODO FIND
func (rs *RepositorySuite) TestFindyByID() {
rows := sqlmock.NewRows([]string{"id", "name", "age", "document"}).
AddRow(
rs.person.ID,
rs.person.Name,
rs.person.Age,
rs.person.Document)
rs.mock.ExpectQuery(
regexp.QuoteMeta(`SELECT * FROM "people" WHERE "people"."id" = $1`)).
WithArgs().
WillReturnRows(rows)
p, err := rs.repo.FindByID(rs.person.ID)
assert.NoError(rs.T(), err)
assert.Equal(rs.T(), rs.person, p)
}
Executando testify suite
Para finalizar, precisamos escrever uma função de testes do próprio Go. Nela, vamos chamar a função suite.Run para poder executar os testes que escrevemos.
func TestSuite(t *testing.T) {
suite.Run(t, new(RepositorySuite))
}
Pronto. Agora é só executar o go test para que nossa suite de testes seja executada.
Qualquer dúvida, é só deixar nos comentários.
Até a próxima!
Faça parte da comunidade!
Receba os melhores conteúdos sobre Go, Kubernetes, arquitetura de software, Cloud e esteja sempre atualizado com as tendências e práticas do mercado.
Livros Recomendados
Abaixo listei alguns dos melhores livros que já li sobre GO.

