Testes de integração verifique se as partes da sua API funcionam juntas corretamente (rotas, banco de dados e lógica de negócios) fazendo solicitações reais e verificando respostas reais. Ao contrário dos testes unitários (que simulam tudo), os testes de integração detectam bugs nos limites. Este guia mostra como escrevê-los bem.
📋 Table of Contents
Testes de Unidade vs Integração
| Aspecto | Teste de Unidade | Teste de Integração |
|---|---|---|
| Escopo | Uma função isolada | Várias partes juntas (rota + DB) |
| Dependências | Zombado | Banco de dados real (ou de teste) |
| Velocidade | Muito rápido | Mais lento (E/S real) |
| Capturas | Erros lógicos | Bugs de integração/fiação |
Você deseja ambos – testes de unidade para lógica, testes de integração para verificar se todo o fluxo de solicitação-resposta funciona.
Node.js: Testando com Superteste
npm install --save-dev jest supertest
// Export your app WITHOUT calling listen() so tests can use it
// app.js
const express = require('express');
const app = express();
app.use(express.json());
app.get('/users/:id', getUser);
app.post('/users', createUser);
module.exports = app; // export the app
// server.js (separate) starts it
const app = require('./app');
app.listen(3000);
// users.test.js
const request = require('supertest');
const app = require('./app');
const db = require('./db');
describe('Users API', () => {
beforeEach(async () => {
await db.reset(); // clean database before each test
});
afterAll(async () => {
await db.close();
});
it('creates a user', async () => {
const res = await request(app)
.post('/users')
.send({ name: 'Alice', email: 'alice@example.com' });
expect(res.status).toBe(201);
expect(res.body).toMatchObject({ name: 'Alice' });
expect(res.body.id).toBeDefined();
});
it('returns 404 for missing user', async () => {
const res = await request(app).get('/users/999');
expect(res.status).toBe(404);
});
it('validates required fields', async () => {
const res = await request(app).post('/users').send({});
expect(res.status).toBe(400);
expect(res.body.error).toBeDefined();
});
});
Python: Testando com pytest e TestClient
pip install pytest httpx
# test_users.py (FastAPI example)
import pytest
from fastapi.testclient import TestClient
from app.main import app
from app.database import get_test_db
client = TestClient(app)
@pytest.fixture(autouse=True)
def reset_db():
db = get_test_db()
db.reset()
yield
db.close()
def test_create_user():
response = client.post("/users", json={
"name": "Alice", "email": "alice@example.com"
})
assert response.status_code == 201
data = response.json()
assert data["name"] == "Alice"
assert "id" in data
def test_get_missing_user():
response = client.get("/users/999")
assert response.status_code == 404
def test_validation_error():
response = client.post("/users", json={})
assert response.status_code == 422
Usando um banco de dados de teste
Os testes de integração precisam de um banco de dados real (de teste) — separado do desenvolvimento e da produção:
# Spin up a test database with Docker
docker run -d --name test-db -p 5433:5432 \
-e POSTGRES_DB=testdb -e POSTGRES_PASSWORD=test \
postgres:15-alpine
# Point tests at it via environment
DATABASE_URL=postgresql://postgres:test@localhost:5433/testdb
// Fast reset using transactions (rollback after each test)
beforeEach(async () => {
await db.query('BEGIN');
});
afterEach(async () => {
await db.query('ROLLBACK'); // undo all changes — fast and clean
});
Testando endpoints autenticados
describe('Protected routes', () => {
let token;
beforeAll(async () => {
const res = await request(app)
.post('/login')
.send({ email: 'test@example.com', password: 'password' });
token = res.body.accessToken;
});
it('allows access with valid token', async () => {
const res = await request(app)
.get('/protected')
.set('Authorization', `Bearer ${token}`);
expect(res.status).toBe(200);
});
it('rejects without token', async () => {
const res = await request(app).get('/protected');
expect(res.status).toBe(401);
});
});
Executando testes de integração em CI
# GitHub Actions with a service database
jobs:
test:
runs-on: ubuntu-latest
services:
postgres:
image: postgres:15
env:
POSTGRES_DB: testdb
POSTGRES_PASSWORD: test
ports: ['5432:5432']
options: --health-cmd pg_isready --health-interval 10s
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: '20' }
- run: npm ci
- run: npm run test:integration
env:
DATABASE_URL: postgresql://postgres:test@localhost:5432/testdb
Melhores Práticas
- Testes de isolamento: Cada teste deve ser independente — redefina o banco de dados entre os testes
- Teste o contrato: Verifique códigos de status, formato de resposta e casos de erro
- Cubra caminhos de erro: Teste 400, 401, 404 e falhas de validação, não apenas o caminho feliz
- Use um banco de dados de teste real: Não zombe do banco de dados em testes de integração
- Mantenha-os razoavelmente rápidos: A reversão de transações é mais rápida do que truncar tabelas
- Execute em CI: Os testes de integração detectam bugs de fiação que os testes de unidade não percebem
Perguntas Frequentes
P: Devo simular o banco de dados em testes de integração?
R: Não — o objetivo é verificar interações reais, incluindo o banco de dados. Use um banco de dados de teste separado. Zombar disso transforma-o em um teste de unidade e perde os bugs de integração que você está tentando detectar.
P: Como posso manter os testes de integração rápidos?
R: Use a reversão de transação entre testes em vez de truncar/recriar tabelas. Execute testes em paralelo onde o isolamento permitir. Use um banco de dados em contêiner e mantenha-o pequeno.
P: De quantos testes de integração eu preciso?
R: Cubra os caminhos críticos de cada endpoint — sucesso, erros de validação, falhas de autenticação e casos não encontrados. Os testes unitários tratam de detalhes lógicos; os testes de integração cobrem os principais comportamentos de cada endpoint.
P: Testes de integração ou testes E2E?
R: Os testes de integração verificam a camada API (rotas + banco de dados). Os testes E2E verificam os fluxos completos do usuário por meio da IU. Ambos têm valor – têm mais testes de integração do que E2E, pois são mais rápidos e focados.
P: Como posso testar chamadas de API externas?
R: Simule essas chamadas específicas (você não quer que os testes atinjam serviços de terceiros) enquanto mantém seu banco de dados real. Simule apenas dependências externas verdadeiras, não seu próprio banco de dados.
Conclusão
Os testes de integração verificam se sua API funciona de ponta a ponta – rotas, banco de dados e lógica juntos – detectando bugs de fiação que os testes de unidade não percebem. UsarSuperteste com Jest (Node.js) ou pytest com TestClient (Python), aponte-os para um banco de dados de teste real (redefinição entre testes por meio de reversão de transação para aumentar a velocidade) e cubra casos de sucesso, erros de validação, autenticação e caminhos não encontrados. Execute-os em CI com um banco de dados de serviço. Combinados com testes de unidade para lógica, os testes de integração dão a você a confiança de que sua API realmente funciona conforme o esperado pelos clientes.
🔗 Share this article
✍️ Leave a Comment