Estrategias de Teste - Piramide de Testes para Garantir Qualidade

16 min leitura | 2025.12.01

Por que Testes sao Importantes

Testes sao um meio importante para garantir a qualidade do codigo e prevenir regressoes (bugs de regressao).

Codigo sem testes:

  • Refatoracao assustadora
  • Impacto das mudancas desconhecido
  • Bugs descobertos em producao

Piramide de Testes

Um modelo que mostra os tipos de teste e a proporcao recomendada.

flowchart TB
    subgraph Pyramid["Piramide de Testes"]
        E2E["Testes E2E<br/>Poucos (10%)<br/>Alto custo, lentos, instaveis"]
        Integration["Testes de Integracao<br/>Moderados (20%)<br/>Custo medio, velocidade media"]
        Unit["Testes Unitarios<br/>Muitos (70%)<br/>Baixo custo, rapidos, estaveis"]

        E2E --> Integration --> Unit
    end

Testes Unitarios

Testam funcoes ou classes individualmente de forma isolada.

Caracteristicas

ItemTeste Unitario
AlvoFuncoes, classes, modulos
VelocidadeMuito rapido (milissegundos)
EstabilidadeAlta
CoberturaEstreita (funcionalidade unica)

Exemplo de Implementacao

// Codigo a ser testado
function calculateTotal(items, taxRate) {
  const subtotal = items.reduce((sum, item) => sum + item.price * item.quantity, 0);
  return Math.round(subtotal * (1 + taxRate));
}

// Teste
describe('calculateTotal', () => {
  it('calcula o valor total dos produtos', () => {
    const items = [
      { price: 100, quantity: 2 },
      { price: 200, quantity: 1 }
    ];
    expect(calculateTotal(items, 0.1)).toBe(440);
  });

  it('retorna 0 para array vazio', () => {
    expect(calculateTotal([], 0.1)).toBe(0);
  });

  it('retorna subtotal quando taxa e 0%', () => {
    const items = [{ price: 100, quantity: 1 }];
    expect(calculateTotal(items, 0)).toBe(100);
  });
});

Padrao AAA

it('cria um usuario', () => {
  // Arrange (Preparar)
  const userData = { name: 'Alice', email: 'alice@example.com' };

  // Act (Agir)
  const user = createUser(userData);

  // Assert (Verificar)
  expect(user.id).toBeDefined();
  expect(user.name).toBe('Alice');
});

Testes de Integracao

Testam se multiplos componentes funcionam juntos corretamente.

Caracteristicas

ItemTeste de Integracao
AlvoAPI, integracao com banco de dados, servicos externos
VelocidadeModerada (segundos)
EstabilidadeModerada
CoberturaModerada

Exemplo de Implementacao (API)

describe('POST /api/users', () => {
  beforeEach(async () => {
    await db.users.deleteMany();
  });

  it('cria um novo usuario', async () => {
    const response = await request(app)
      .post('/api/users')
      .send({ name: 'Alice', email: 'alice@example.com' })
      .expect(201);

    expect(response.body.id).toBeDefined();
    expect(response.body.name).toBe('Alice');

    // Confirma que foi salvo no banco de dados
    const user = await db.users.findById(response.body.id);
    expect(user).not.toBeNull();
  });

  it('retorna erro para email duplicado', async () => {
    await db.users.create({ name: 'Bob', email: 'alice@example.com' });

    await request(app)
      .post('/api/users')
      .send({ name: 'Alice', email: 'alice@example.com' })
      .expect(409);
  });
});

Testes E2E (End-to-End)

Testam a aplicacao inteira do ponto de vista do usuario.

Caracteristicas

ItemTeste E2E
AlvoFluxo completo do usuario
VelocidadeLento (minutos)
EstabilidadeBaixa (propenso a flakiness)
CoberturaAmpla

Exemplo de Implementacao (Playwright)

import { test, expect } from '@playwright/test';

test('faz login e exibe dashboard', async ({ page }) => {
  // Navega para pagina de login
  await page.goto('/login');

  // Preenche formulario
  await page.fill('[name="email"]', 'user@example.com');
  await page.fill('[name="password"]', 'password123');
  await page.click('button[type="submit"]');

  // Confirma redirecionamento para dashboard
  await expect(page).toHaveURL('/dashboard');
  await expect(page.locator('h1')).toContainText('Dashboard');
});

test('busca produto e compra', async ({ page }) => {
  await page.goto('/');

  // Busca
  await page.fill('[name="search"]', 'Notebook');
  await page.click('button[type="submit"]');

  // Adiciona produto ao carrinho
  await page.click('[data-testid="add-to-cart"]');

  // Vai para o carrinho
  await page.click('[data-testid="cart-icon"]');
  await expect(page.locator('.cart-item')).toHaveCount(1);
});

Mock/Stub

Simula dependencias externas para isolar os testes.

// Mock de API externa
jest.mock('./paymentService', () => ({
  processPayment: jest.fn().mockResolvedValue({ success: true, transactionId: 'tx_123' })
}));

import { processPayment } from './paymentService';

it('processa pagamento', async () => {
  const result = await checkout(order);

  expect(processPayment).toHaveBeenCalledWith({
    amount: order.total,
    currency: 'BRL'
  });
  expect(result.transactionId).toBe('tx_123');
});

Desenvolvimento Orientado a Testes (TDD)

Metodologia de desenvolvimento onde se escreve o teste antes da implementacao.

flowchart LR
    Red["Red<br/>Escrever teste que falha"] --> Green["Green<br/>Implementacao minima para passar"] --> Refactor["Refactor<br/>Melhorar codigo"]
    Refactor --> Red

Exemplo de TDD

// 1. Red: Escrever teste que falha
it('erro quando senha tem menos de 8 caracteres', () => {
  expect(() => validatePassword('1234567')).toThrow('Password too short');
});

// 2. Green: Implementacao minima
function validatePassword(password) {
  if (password.length < 8) {
    throw new Error('Password too short');
  }
}

// 3. Refactor: Melhorar codigo conforme necessario

Cobertura

Indicador que mostra quanto do codigo e coberto pelos testes.

Tipo de CoberturaDescricao
Cobertura de LinhaPorcentagem de linhas executadas
Cobertura de BranchPorcentagem de ramificacoes executadas
Cobertura de FuncaoPorcentagem de funcoes executadas

Meta de Cobertura

80% e uma meta comum

Porem:

  • Nao e necessario buscar 100%
  • Alta cobertura != alta qualidade de testes
  • Priorize cobrir caminhos importantes

Como Escolher a Estrategia de Testes

CenarioTeste a Priorizar
Logica de negocio complexaTestes Unitarios
Muitas integracoes externasTestes de Integracao
UI importanteTestes E2E
Manutencao de codigo legadoE2E para criar rede de seguranca

Resumo

Uma estrategia de testes eficaz e aquela que, consciente da piramide de testes, distribui equilibradamente os testes em cada nivel. Centralize nos testes unitarios, confirme integracoes com testes de integracao e garanta fluxos importantes do usuario com testes E2E. Testes nao sao algo que reduz a velocidade de desenvolvimento, mas sim um investimento que melhora a qualidade e eficiencia de desenvolvimento a longo prazo.

← Voltar para a lista