🌐 Detecting your location…
📢 Advertisement — Configure AdSense in Appearance → Customize → AdSense Settings

Como escrever testes de integração para uma API REST em 2026: guia completo

⏱️6 min read  ·  1,153 words

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.

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.

✍️ Leave a Comment

Your email address will not be published. Required fields are marked *

🌐 Read in:🇩🇪 Deutsch🇧🇷 Português🇸🇦 العربية🇮🇳 हिन्दी🇧🇩 বাংলা