Pular para o conteúdo

Testes de API

Uma tela de carrinho que soma errado pode ter dois culpados: o componente que mostra o número, ou a API que calculou esse número. Testar só pela tela não distingue os dois. Testar a API direto, sem passar pelo navegador, sim.

Esta nota assume o básico de HTTP e JSON e volta ao framework já apresentado em Framework com Playwright e TypeScript.

Três motivos para não deixar tudo por conta da UI:

  • Velocidade. Uma chamada HTTP responde em milissegundos. Abrir navegador, renderizar página e esperar elemento aparecer custa muito mais.
  • Estabilidade. Teste de API não quebra porque um botão mudou de lugar ou uma animação atrasou um clique. Ele quebra quando o contrato da API muda, que é exatamente o que você quer saber.
  • Setup e verificação de cenário. Antes de um teste de UI, uma chamada de API cria o pedido, o usuário ou o produto que o teste precisa. Depois, outra chamada confere se o estado no banco ficou correto, sem precisar navegar até uma tela para ler o valor.

Isso não substitui o teste de UI, só tira dele o trabalho que ele faz pior. Vale lembrar a pirâmide de testes: testes de API ficam numa camada mais rápida e barata que o E2E, e mais perto do comportamento real que o teste de unidade isolado.

Uma API REST expõe recursos (um pedido, um usuário, um produto) e você opera sobre eles com verbos HTTP:

VerboUso típico
GETbuscar um recurso, sem alterar nada
POSTcriar um recurso novo
PUTsubstituir um recurso inteiro
PATCHalterar parte de um recurso
DELETEremover um recurso

A resposta vem com um código de status, que já avisa o resultado antes de olhar o corpo:

  • 2xx: deu certo (200 OK, 201 Created, 204 No Content)
  • 4xx: erro de quem pediu (400 Bad Request, 401 Unauthorized, 404 Not Found)
  • 5xx: erro do servidor (500 Internal Server Error)

O corpo da requisição e da resposta quase sempre é JSON:

{
"id": 42,
"nomeCliente": "Ana",
"itens": [{ "produto": "Caneca", "quantidade": 2 }]
}

Testar uma API é, no fundo, confirmar três coisas: o verbo certo no caminho certo devolve o status certo, com o corpo certo.

A maioria das APIs exige provar quem está chamando. As formas mais comuns:

  • API key: uma chave fixa enviada num header, geralmente para identificar a aplicação que chama, não a pessoa.
  • Bearer token / JWT: um token enviado no header Authorization: Bearer <token>, obtido num login prévio. O JWT (JSON Web Token) é o formato mais comum, e carrega informação sobre quem é o usuário dentro do próprio token.
  • Basic auth: usuário e senha codificados no header Authorization. Simples, mas só seguro sobre HTTPS, e cada vez mais raro em API nova.

Para não repetir login em cada teste, uma prática comum é autenticar uma vez, guardar o token (ou os cookies, no caso de testes de UI) e reaproveitar nos testes seguintes. É a mesma ideia do storageState do Playwright, que aparece em Browser, Context e Page: autentique uma vez, reaproveite a sessão nos testes que vêm depois.

O Postman é a ferramenta mais usada para explorar e testar API manualmente, antes (ou em vez) de escrever código.

  • Coleções: um conjunto de requisições organizadas, geralmente uma por endpoint ou fluxo.
  • Variáveis de ambiente: em vez de escrever a URL e o token fixos em cada requisição, você usa {{base_url}} e {{token}}, e troca o ambiente (dev, staging, produção) sem editar nada.
  • Scripts de teste: cada requisição pode ter um script em JavaScript que roda depois da resposta chegar, verificando status e corpo:
pm.test("status é 200", function () {
pm.response.to.have.status(200);
});
pm.test("corpo tem o nome do cliente", function () {
const corpo = pm.response.json();
pm.expect(corpo.nomeCliente).to.eql("Ana");
});
  • Newman: o executor de linha de comando do Postman. Com ele, a coleção inteira roda no CI, sem abrir a interface gráfica:
Terminal window
newman run colecao-pedidos.json -e ambiente-staging.json

O Postman brilha na fase exploratória, quando você ainda está entendendo a API. Para uma suíte de testes que mora no repositório, versionada junto com o código, o Playwright costuma ganhar.

O Playwright não serve só para navegador. Ele tem uma classe própria para fazer requisições HTTP puras, sem abrir página nenhuma: APIRequestContext.

No Playwright Test, isso chega pronto pela fixture request:

import { test, expect } from "@playwright/test";
test("cria e busca um pedido", async ({ request }) => {
const criacao = await request.post("/pedidos", {
data: { itens: [{ produto: "Caneca", quantidade: 2 }] },
});
expect(criacao.ok()).toBeTruthy(); // status entre 200 e 299
const pedido = await criacao.json();
const busca = await request.get(`/pedidos/${pedido.id}`);
expect(busca.status()).toBe(200);
expect(await busca.json()).toMatchObject({ itens: expect.any(Array) });
});

Repare que request já respeita o baseURL configurado no playwright.config.ts, então o teste escreve só o caminho (/pedidos), não a URL inteira.

O ganho de usar o Playwright para isso, em vez de uma ferramenta separada, é combinar API e UI no mesmo teste: a API cria o pedido, a UI confere que ele aparece na tela certa, tudo no mesmo arquivo, com a mesma sessão autenticada.

Checar só o status 200 é o mínimo. Validar de verdade envolve conferir o corpo da resposta: os campos certos, com o tipo certo, no lugar certo. Um endpoint que devolve 200 com um JSON vazio passou no status e falhou no que importa.

Isso aproxima o teste de API do teste de contrato: o teste de API que você escreve manualmente confere uma resposta específica, enquanto o contrato formaliza isso entre times, para dois serviços que evoluem juntos. Num time só, testar a resposta da própria API já cobre boa parte do risco; entre times diferentes, o contrato formal compensa o esforço.

  • Teste o contrato, não a implementação: confira o formato da resposta, não como o servidor calculou internamente.
  • Isole o dado de teste: cada teste cria o próprio recurso (um pedido, um usuário) em vez de depender de um registro fixo que outro teste pode alterar.
  • Verifique o caminho de erro: um 404 para recurso inexistente, um 400 para corpo inválido. É onde a maioria dos bugs de API mora.
  • Não deixe token em código: leia credenciais de variável de ambiente, nunca escreva um token fixo no teste.
  • Combine com UI com parcimônia: use API para montar cenário e checar estado, e deixe a UI para o que só faz sentido testar na tela.