O ATDD inverte a ordem usual: o QA escreve um teste de aceitação no Playwright antes de a feature existir. O teste falha e a feature está pronta quando passa. Essa única mudança move o QA de verificar trabalho finalizado para definir o que "pronto" significa.

O ciclo TDD: Red, Green, Refactor

O TDD segue um ciclo estrito de três etapas:

1. Red — escreva um teste que falha (porque a feature ainda não existe)

2. Green — escreva o código mínimo para fazer o teste passar

3. Refactor — limpe o código mantendo os testes verdes

Esse ciclo se repete para cada pequeno pedaço de funcionalidade.

// Fase Red: escrever um teste que falha
test('calculateDiscount aplica 10% para o código SAVE10', () => {
  const result = calculateDiscount(100, 'SAVE10');
  expect(result).toBe(90);
});

// Rodar esse teste falha: calculateDiscount não está definida

// Fase Green: escrever código mínimo para passar
function calculateDiscount(price: number, code: string): number {
  if (code === 'SAVE10') {
    return price * 0.9;
  }
  return price;
}

// Agora o teste passa

// Fase Refactor: limpar sem quebrar o teste
const DISCOUNT_CODES: Record<string, number> = {
  SAVE10: 0.1,
  SAVE20: 0.2,
  SAVE50: 0.5,
};

function calculateDiscount(price: number, code: string): number {
  const discount = DISCOUNT_CODES[code] || 0;
  return price * (1 - discount);
}

// Os testes ainda passam: a refatoração não quebrou nada

Benefícios do TDD que afetam o QA

Código naturalmente testável:

Código escrito com TDD tende a ter funções menores com inputs e outputs claros, mais fáceis de testar em todos os níveis.

Segurança contra regressão:

Todo comportamento está protegido por um teste. Quando o QA encontra um bug, os desenvolvedores podem reproduzi-lo com um teste, corrigir e o teste previne a regressão.

Documentação pelos testes:

Os testes TDD descrevem o que o código deve fazer em cenários específicos. O QA pode ler os testes para entender o comportamento esperado.

Detecção de bugs mais cedo:

Problemas detectados ao escrever testes unitários são ordens de magnitude mais baratos de corrigir do que problemas encontrados em QA ou em produção.

Behavior-Driven Development (BDD)

BDD estende o TDD em direção à camada de negócio. Onde TDD foca em como o código funciona, BDD foca em qual comportamento é necessário.

Os três amigos: desenvolvedor, QA e product manager colaboram para definir o comportamento usando o formato Given/When/Then antes de escrever qualquer código.

Feature: Códigos de desconto

  Scenario: Código de desconto válido reduz o preço
    Given eu tenho um carrinho com itens totalizando R$100
    When aplico o código de desconto "SAVE10"
    Then o total deve ser R$90
    And o valor do desconto deve ser R$10

  Scenario: Código de desconto inválido mostra erro
    Given eu tenho um carrinho com itens totalizando R$100  
    When aplico o código de desconto "INVALIDO"
    Then devo ver "Código de desconto inválido"
    And o total deve permanecer R$100

  Scenario: Código de desconto expirado mostra erro
    Given eu tenho um carrinho com itens totalizando R$100
    When aplico o código de desconto "EXPIRADO20"
    Then devo ver "Este código de desconto expirou"

Como o QA pode aplicar a mentalidade TDD

Mesmo que você não esteja escrevendo testes unitários, pode aplicar a mentalidade TDD.

Escreva casos de teste antes de os testes manuais começarem

Em vez de testes exploratórios do zero, escreva os comportamentos esperados primeiro:

Feature: Reset de Senha

O que eu espero que seja verdade:
1. Digitar um email válido envia um email de reset em até 2 minutos
2. Digitar um email inválido mostra "Email não encontrado"
3. O link de reset expira após 24 horas
4. Usar um link expirado mostra "Link expirado" com opção de solicitar um novo
5. Após o reset bem-sucedido, a senha antiga não funciona mais
6. O link de reset só pode ser usado uma vez

Agora você tem um plano de teste antes de começar a testar.

Desenvolvimento Orientado a Testes de Aceitação (ATDD)

Colabore com os desenvolvedores para escrever testes de aceitação antes de a feature ser construída:

// Escrito antes de a feature existir
test('checkout com cartão válido conclui a compra', async ({ page }) => {
  // Configuração: usuário com itens no carrinho
  // ...

  // Executar checkout
  await page.fill('[data-testid="card-number"]', '4242 4242 4242 4242');
  await page.fill('[data-testid="card-expiry"]', '12/28');
  await page.fill('[data-testid="card-cvc"]', '123');
  await page.click('[data-testid="pay-now"]');
  
  // Resultados esperados
  await expect(page).toHaveURL('/order-confirmation');
  await expect(page.getByTestId('order-number')).toBeVisible();
  await expect(page.getByTestId('success-message')).toContainText('Pagamento realizado com sucesso');
});

Esses testes falham até a feature ser construída. Quando passam, a feature está pronta.

Quando os desenvolvedores praticam TDD: o que o QA precisa saber

O que muda para o QA

Cobertura de testes unitários já existe:

Os desenvolvedores já testaram casos extremos no nível do código. O QA pode focar em pontos de integração, fluxos de usuário e lógica de negócio, não em comportamento básico de funções.

Falhas de testes são significativas:

Quando o CI de um time TDD quebra, é específico: "a função X retorna valor errado para o caso extremo Y," não "o app está quebrado em algum lugar."

Refatoração é mais segura:

Com testes unitários abrangentes, o QA não precisa retestar funcionalidades básicas após refatoração: os testes já cobrem isso.

O que o QA ainda precisa fazer

Testes de integração:

Testes unitários testam funções em isolamento. O QA testa como os componentes funcionam juntos: o banco de dados, a API, o frontend, o sistema de email.

Testes do ponto de vista do usuário:

Desenvolvedores testam "o código funciona?" O QA testa "a feature faz sentido para usar?"

Descoberta de casos extremos:

Testes exploratórios de QA encontram cenários que não foram especificados. TDD só cobre o que foi pensado ao escrever os testes.

Performance e confiabilidade:

TDD não cobre tempos de resposta, usuários simultâneos ou o que acontece sob carga.

TDD prático para automação de testes

Ao construir seu framework de testes, aplique princípios TDD:

// Em vez de escrever o helper completo primeiro, escreva um teste para o que você quer que ele faça
test('helper de login deve redirecionar para o dashboard após login', async ({ page }) => {
  await loginAs(page, 'member');  // Esta função ainda não existe
  
  await expect(page).toHaveURL('/dashboard');
});

// Agora escreva a implementação mínima
async function loginAs(page: Page, role: 'admin' | 'member') {
  const credentials = {
    admin: { email: 'admin@test.com', password: 'AdminPass1' },
    member: { email: 'member@test.com', password: 'MemberPass1' },
  };
  
  await page.goto('/login');
  await page.fill('[data-testid="email"]', credentials[role].email);
  await page.fill('[data-testid="password"]', credentials[role].password);
  await page.click('[data-testid="submit"]');
  await page.waitForURL('/dashboard');
}

Isso previne over-engineering. Você constrói exatamente o que é necessário, e o teste confirma que funciona.

A pirâmide de testes no contexto TDD

TDD molda diretamente a pirâmide de testes:

         /\
        /E2E\          ← Automação QA (menos, mais lentos)
       /------\
      / Integr.\       ← Testes de integração (moderados)
     /----------\
    /  Unit Tests \    ← Output do TDD (muitos, rápidos)
   /--------------\

TDD produz a base ampla de testes unitários. O QA constrói as camadas de integração e E2E em cima. Juntos formam uma pirâmide onde a maioria dos bugs é capturada barato no nível unitário, com um conjunto menor e focado de testes E2E mais caros.

Resumo

  • Ciclo TDD: Red (teste que falha) → Green (fazer passar) → Refactor (limpar)
  • TDD produz código naturalmente testável e bem estruturado
  • BDD estende TDD em direção ao comportamento de negócio com cenários Given/When/Then
  • ATDD: o QA escreve testes de aceitação antes do desenvolvimento começar; os testes falham até a feature ser construída
  • Quando os desenvolvedores praticam TDD, o QA muda o foco para integração, fluxos de usuário e casos extremos
  • Aplique a mentalidade TDD à automação de testes: escreva a interface de teste primeiro, depois implemente

TDD e QA são complementares, não concorrentes. TDD captura bugs no nível unitário cedo. O QA captura problemas de integração e experiência do usuário. Juntos produzem software que funciona corretamente em todos os níveis.

→ Veja também: Desenvolvimento Orientado a Testes: O Guia do Engenheiro QA | Testes Shift-Left: O que Significa e Como Praticar | A Pirâmide de Testes Explicada para Engenheiros QA