Por que os testes E2E são o seu seguro de vida
\n\nImagine: você escreveu um microsserviço incrível em Go. Os testes unitários estão verdes, os de integração também. Você faz o deploy em produção e… os usuários reclamam que o carrinho não é limpo após o pagamento. Familiar? O problema é que os testes E2E de aplicações Go frequentemente ficam para "depois". E é uma pena.
\n\nTestes de ponta a ponta (End-to-End) são a única maneira de verificar se o seu sistema funciona como um todo integrado: desde a requisição HTTP até a gravação no banco de dados e vice-versa. Neste artigo, não vamos apenas falar sobre teoria — vou mostrar exemplos reais de código em Go que você pode copiar e executar hoje mesmo.
\n\nO que são testes E2E no contexto do Golang?
\n\nTestes E2E em Go são a verificação de um cenário completo do usuário: iniciar a aplicação, executar a lógica de negócio, interagir com serviços externos (BD, cache, filas) e verificar o resultado. Ao contrário dos testes unitários, não simulamos o banco de dados — subimos um PostgreSQL real em um contêiner.
\n\nQual a diferença entre E2E e testes de integração?
\n\nFrequentemente esses conceitos são confundidos. Vamos esclarecer de uma vez por todas:
\n\n- \n
- Testes unitários — verificam uma única função. Rápidos e isolados. \n
- Testes de integração — verificam a combinação de módulos (ex: repositório + BD). \n
- Testes E2E — sobem a aplicação inteira e simulam ações de um usuário real. \n
Para testes de ponta a ponta em Golang, usaremos o pacote padrão testing juntamente com utilitários poderosos: testcontainers-go e dockertest.
Configuração do ambiente: Docker Compose e Testcontainers
\n\nA maneira mais simples de organizar testes e2e em go é usar Docker. Você tem dois caminhos:
\n\nOpção 1: Docker Compose (para CI/CD)
\n\nCrie um arquivo docker-compose.test.yml:
version: '3.8'\nservices:\n db:\n image: postgres:15-alpine\n environment:\n POSTGRES_DB: testdb\n POSTGRES_USER: test\n POSTGRES_PASSWORD: test\n ports:\n - "5432:5432"\n \n app:\n build: .\n depends_on:\n - db\n environment:\n DATABASE_URL: "postgres://test:test@db:5432/testdb?sslmode=disable"\n ports:\n - "8080:8080"\n\n\nOpção 2: Testcontainers (para desenvolvimento local)
\n\nA biblioteca testcontainers-go permite subir contêineres diretamente dos testes. Esta é minha favorita — os testes gerenciam a infraestrutura por conta própria.
// setup_test.go\npackage e2e_test\n\nimport (\n "context"\n "testing"\n "time"\n\n "github.com/testcontainers/testcontainers-go"\n "github.com/testcontainers/testcontainers-go/wait"\n)\n\nfunc setupPostgres(t *testing.T) string {\n t.Helper()\n \n ctx := context.Background()\n \n req := testcontainers.ContainerRequest{\n Image: "postgres:15-alpine",\n ExposedPorts: []string{"5432/tcp"},\n Env: map[string]string{\n "POSTGRES_DB": "testdb",\n "POSTGRES_USER": "test",\n "POSTGRES_PASSWORD": "test",\n },\n WaitingFor: wait.ForLog("database system is ready to accept connections").\n WithStartupTimeout(30 * time.Second),\n }\n \n container, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{\n ContainerRequest: req,\n Started: true,\n })\n if err != nil {\n t.Fatalf("failed to start container: %v", err)\n }\n \n t.Cleanup(func() {\n container.Terminate(ctx)\n })\n \n host, _ := container.Host(ctx)\n port, _ := container.MappedPort(ctx, "5432")\n \n return "postgres://test:test@" + host + ":" + port.Port() + "/testdb?sslmode=disable"\n}\n\n\n