Como escrever uma suite de testes em Go
Como escrever suites de teste em Go usando o pacote testify

Na parte 2 da série "Pensando em testes" fiz uma menção ao conceito de suite de testes. Agora vou te ensinar a implementar uma usando Go. Uma suite de testes nada mais é que um agregador de outros testes, e este é um recurso importante para que esta parte vital do código do seu projeto seja mais fácil de ser mantida.

Acompanhe a nossa série "Pensando em testes"!
Ingredientes

- Go 1.24 ou posterior (mas você pode substituir por versões mais antigas da linguagem)
- Pacote testify - https://github.com/stretchr/testify (versão 1.10.0)
Passo a passo
Identifique os testes
O primeiro passo consiste em identificar o conjunto de testes que irão validar uma funcionalidade ou comportamento específico do seu sistema.
No nosso caso de exemplo iremos tratar de testes que validem o processo de autenticação de usuários na nossa plataforma. Iremos tratar aqui testes de integração, que realizam chamadas contra o nosso endpoint de autenticação. Já pensamos em alguns casos:
- Autenticação mal sucedida ao informar credenciais inválidas
- Uma autenticação bem sucedida fornecendo credenciais válidas
- Autenticação bem sucedida de um usuário associado a um tenant.
- Autenticação mal sucedida de um usuário que tenta acessar um tenant que não é o seu.
Escrevendo a suite de testes
Se você já escreveu testes em Go, a situação não muda muito: a principal diferença é que começamos pela definição de uma struct. E é esta struct que conterá todos os métodos que corresponderão aos testes que iremos escrever.
Criando a struct principal para nossa suite
Comece criando um arquivo de testes seguindo o padrão do Go para que estes possam ser identificados: um simples arquivo que termine com o sufixo "test". Em nosso exemplo se chamará auth_suite_test.go
e que será similar ao exemplo a seguir:
package tests
import (
"encoding/json" //apenas para nosso exempl
"fmt" // apenas para nosso exemplo
"net/http" // apenas para nosso exemplo
"net/http/httptest" // apenas para nosso exemplo
"strings" //apenas para nosso exemplo
"testing" // você precisa do testing do Go
"github.com/gin-gonic/gin" // apenas par anosso exemplo
"github.com/stretchr/testify/suite" // este você precisa! :)
)
/*
Contempla todos os casos de testes de acesso na plataforma em
um teste suite.
*/
type AcessoTestSuite struct {
router *gin.Engine
suite.Suite
}
Observe que importamos o pacote github.com/stretchr/sute
e na sequência criamos a nossa struct que contém dois atributos: o Engine do Gin, presente no nosso projeto de exemplo, e também um atributo do tipo suite.Suite
que iremos usar na execução dos nossos testes.
Escrevendo os nossos testes
func (suite *AcessoTestSuite) TestAcessoNegadoUsuarioInexistente() {
request := utils.CredentialsRequest{
Username: "inexistente@inexistente.com",
Password: "SuperInexistenteMesmo!",
}
w := httptest.NewRecorder()
requestJson, _ := json.Marshal(request)
requestJsonString := string(requestJson)
req, _ := http.NewRequest("POST", "/api/v1/auth", strings.NewReader(requestJsonString))
req.Header.Set("Content-Type", "application/json")
suite.router.ServeHTTP(w, req)
suite.Equal(http.StatusUnauthorized, w.Code)
}
Observe que é mantido o padrão da nomenclatura de nomes de testes do Go: nossa função começa com o prefixo Test
e está associada à struct. A partir dela podemos acessar também assertions, como Equal
, tal como você pode ver no nosso exemplo. Nada demais.
Visite o site do projeto para aprender mais: http://github.com/stretchr/testify
Na sequência, escreva os demais testes seguindo os padrões acima.
Preparo da suite de testes - SetupAllSuite
Notou que na suite de testes eu uso o roteador do Gin para realizar minha validação? É possível definir uma função que será executada antes de todos os testes da suite. Isto é particularmente útil no caso de testes integrados, aonde você pode executar código como migrations, início de serviços externos, etc.
O nome da função a ser implementada se chama SetupAllSuite
, e você pode ver um exemplo de implementação no código abaixo:
func (suite *AcessoTestSuite) SetupAllSuite() {
fmt.Println("Setup da suite de testes")
err := setup.SetupTests()
suite.Nil(err)
suite.router = endpoints.SetupRouter()
fmt.Println("Setup da suite de testes realizada com sucesso")
}
É ali que já definimos o valor do atributo router
da struct AcessoTestSuite
e também executamos uma única vez - para todos os testes - o código de inicialização da suite: em nosso caso preparo do banco de dados (do módulo setup que menciono ali, específico da nossa situação).
Limpando o caos que sua suite de testes pode ter craido - TearDownAllSuite
É o oposto de SetupSuite
: você escreve nesta função o código que irá limpar as estruturas de dados, registros em banco de dados ou qualquer coisa que sua suite de testes pode ter executado.
Exemplo simples? Bora lá:
func (suite *AcessoTestSuite) TearDownAllSuite() {
// código fictício
suite.transaction.rollback()
}
Finalmente, executando a suite
Fácil: basta escrever um teste, fora da suite, que a inicie, tal como no exemplo a seguir:
func TestAcessoTestSuite(t *testing.T) {
suite.Run(t, new(AcessoTestSuite))
}
Você usa a função Run
, da struct suite
, presente no módulo que você importou como github.com/stretchr/testify/suite
para executar a instância da struct que criamos no início desta receita.
Concluindo com dica
Nesta receita apenas menciono o pacote testify
, mas ele vai muito além: na nossa experiência é quase um substituto para a biblioteca de testes padrão do Go.
Dá uma lida na documentação presente no site oficial, você não vai se arrepender: https://github.com/stretchr/testify
Para ver mais sobre os métodos relativos à execução de suites de teste, acesse este link: https://pkg.go.dev/github.com/stretchr/testify/suite#Suite