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!