SDD e TDD: diferenças e o papel dos testes com agentes

SDD e TDD: diferenças e o papel dos testes com agentes

SDD e TDD aparecem juntos em quase toda conversa sobre desenvolvimento com agentes de IA. Por isso, a pergunta mais comum hoje é se uma abordagem torna a outra obsoleta.

A resposta curta é não, porque as duas trabalham em níveis diferentes do mesmo problema. Enquanto o TDD valida unidades e contratos locais no código, o SDD define intenção, comportamento sistêmico e restrições operacionais para o agente.

Neste artigo, você entende o escopo de cada abordagem e onde elas se encontram. Além disso, vê na prática como o SDD gera a suíte do TDD antes de qualquer linha de implementação.

O que muda quando um agente escreve o código

Durante anos, o desenvolvedor escreveu cada linha de código e, por consequência, carregou a intenção do sistema na própria cabeça. Com agentes de código, essa intenção precisa sair da cabeça e ir para um artefato que a máquina consiga ler.

O problema é que um prompt solto vira contexto descartável. Na sessão seguinte, o agente não lembra das decisões tomadas, das regras de negócio combinadas nem das restrições que você explicou com cuidado.

Esse é o terreno onde o vibe coding funciona para protótipos e falha em produção. O código compila, os testes que o próprio agente escreveu passam, mas o sistema não faz o que o negócio pediu.

Por isso, a discussão sobre SDD e TDD ganhou força justamente agora. As duas abordagens tentam resolver a mesma dor, que é tornar a intenção verificável antes de o código existir.

No entanto, elas atacam essa dor em camadas diferentes. Entender essas camadas é o primeiro passo para usar cada uma no lugar certo.

O que o TDD valida no código

O TDD, ou Test Driven Development, é uma disciplina de design guiada por testes automatizados. Você escreve um teste que falha, implementa o mínimo para ele passar e, em seguida, refatora com segurança.

Esse ciclo curto de vermelho, verde e refatoração acontece em minutos. Na prática, cada teste fixa um comportamento pequeno, como o retorno de um método ou uma regra de uma entidade.

A própria Microsoft segue essa abordagem no tutorial de testes de unidade com xUnit no .NET. Primeiro vem o teste que falha, depois o código suficiente para ele passar.

O alcance do TDD, portanto, é local. Ele responde se uma unidade faz o que você acabou de afirmar, mas não responde se o sistema inteiro entrega o que o negócio pediu.

Além disso, o TDD pressupõe que alguém já sabe qual comportamento testar. Quando o requisito é ambíguo, o teste apenas cristaliza a ambiguidade em código.

Ainda assim, o valor do TDD continua enorme. Testes de unidade rodam rápido, isolam falhas e funcionam como rede de proteção contra regressões, inclusive quando quem altera o código é um agente.

O que o SDD define para o agente

O SDD, ou Spec Driven Development, coloca a especificação como fonte da verdade do desenvolvimento. Assim, o código passa a ser a expressão dessa especificação em uma linguagem e em um framework específicos.

Em vez de pedir uma funcionalidade em um prompt, você descreve o que o sistema deve fazer e por quê. Depois, o agente transforma essa descrição em plano técnico, tarefas e implementação.

O Spec Kit do GitHub é a ferramenta mais conhecida desse fluxo. Ele organiza o trabalho em etapas como constitution, specify, plan, tasks e implement, e cada etapa gera um artefato versionado no repositório.

Essa especificação cobre três dimensões que o TDD não alcança sozinho. Primeiro, vem a intenção, ou seja, qual problema do usuário a funcionalidade resolve.

Depois, entra o comportamento sistêmico, que envolve fluxos completos, integrações e critérios de aceitação. Por fim, aparecem as restrições operacionais, como segurança, performance, padrões de arquitetura e regras da empresa.

Essas restrições ficam na constitution, um documento com princípios que o agente precisa respeitar em toda funcionalidade. Se quiser adaptar esse fluxo à realidade do seu time, veja como funcionam as extensões do Spec Kit com presets, bundles e workflows.

SDD e TDD lado a lado

Colocar SDD e TDD lado a lado deixa claro que a diferença está no escopo, e não no valor de cada abordagem. A tabela abaixo resume os pontos principais.

Aspecto TDD SDD
Pergunta central A unidade faz o que eu afirmei? Construímos o que combinamos construir?
Artefato inicial Um teste automatizado que falha Uma especificação estruturada e versionada
Escopo Métodos, classes e contratos locais Funcionalidade, fluxos e restrições do sistema
Público Desenvolvedor Time, stakeholders e agente de código
Duração do ciclo Minutos Horas ou dias por funcionalidade
O que garante Correção local e proteção contra regressão Alinhamento entre intenção e implementação
Ponto cego Requisito errado testado com perfeição Spec correta implementada com bugs

Repare na última linha da tabela. O ponto cego de cada abordagem é exatamente o que a outra cobre, e por isso a comparação entre SDD e TDD não termina em uma escolha.

Um teste perfeito para um requisito mal entendido continua sendo um defeito. Da mesma forma, uma especificação impecável não impede que o agente erre um arredondamento ou esqueça um caso de borda.

Por que o SDD não substitui o TDD

A tese de que o SDD substitui o TDD parte de uma confusão entre especificar e verificar. Uma especificação descreve o comportamento esperado, mas, sozinha, ela não executa nada nem detecta regressão.

Por outro lado, um teste executa, mas só verifica aquilo que alguém decidiu verificar. Sem a especificação, o agente escolhe o que testar com base no próprio entendimento, que pode estar errado.

Existe ainda um risco específico do desenvolvimento com agentes. Quando o mesmo agente escreve o código e só depois escreve os testes, ele tende a testar o que implementou, e não o que você pediu.

Por isso, a relação mais saudável entre SDD e TDD é hierárquica. O SDD define o que precisa ser verdade no sistema, enquanto o TDD prova, unidade por unidade, que o código respeita essa verdade.

O próprio Spec Kit segue essa linha. No documento que descreve a filosofia do Spec Driven Development, o GitHub apresenta uma constitution de exemplo em que testes primeiro é um princípio inegociável.

Em outras palavras, o SDD não elimina o TDD, ele o promove. O teste deixa de ser uma escolha individual do desenvolvedor e passa a ser uma exigência formal que o agente precisa cumprir.

Como o SDD gera a suíte de TDD antes da implementação

Aqui está a parte mais interessante da relação entre SDD e TDD. Se a especificação já descreve comportamentos verificáveis, o agente consegue derivar os testes dela antes de escrever qualquer código de produção.

O fluxo segue uma cadeia de rastreabilidade. Cada cenário da spec vira uma tarefa de teste, cada tarefa vira um teste que falha e só então o agente implementa o código.

Da especificação aos critérios de aceitação

Tudo começa com uma especificação que fala de comportamento, e não de tecnologia. O exemplo a seguir descreve o pagamento de uma fatura com multa por atraso.

## User Scenarios & Testing

### User Story 1 - Pay an invoice (Priority: P1)

**Acceptance Scenarios**:

1. **Given** an open invoice of 100.00 due on 2026-10-10,
   **When** it is paid on 2026-10-15,
   **Then** the total charged is 102.00 (2% late fee).
2. **Given** an invoice that is already paid,
   **When** a new payment is attempted,
   **Then** the payment is rejected with "Invoice already paid".

## Requirements

- **FR-001**: System MUST apply a 2% late fee when payment happens after the due date.
- **FR-002**: System MUST reject any payment for an invoice that is already paid.

Os critérios de aceitação usam o formato Given, When, Then, herdado do BDD. Esse formato funciona bem porque humanos e agentes leem a mesma frase e chegam à mesma interpretação.

Repare também nos requisitos numerados, como FR-001 e FR-002. Esses identificadores criam o elo entre a especificação e os testes, o que permite rastrear qual teste cobre qual regra.

Se a spec tivesse uma ambiguidade, como a data de corte da multa, o template do Spec Kit pediria ao agente uma marcação NEEDS CLARIFICATION. Assim, a dúvida aparece antes do teste, e não depois de um bug em produção.

Do plano às tarefas de teste

Depois da especificação, o agente gera o plano técnico e os contratos da API. Com esse material, o comando de tarefas produz uma lista ordenada em que os testes vêm antes da implementação.

Essa ordem não depende da boa vontade do agente. Na verdade, ela nasce de um princípio da constitution, como no trecho abaixo.

### III. Test-First (NON-NEGOTIABLE)

- Tests MUST be written before any production code.
- Tests MUST be reviewed and approved by the user.
- Tests MUST fail before implementation starts (Red phase).

Com esse princípio ativo, o arquivo de tarefas separa claramente a fase de testes da fase de implementação. Veja um trecho no formato que o comando de tarefas costuma gerar.

## Phase 3.2: Tests First (TDD)
- [ ] T004 [P] Contract test POST /api/invoices/{id}/payments in tests/Billing.Tests/Contract/InvoicePaymentsContractTests.cs
- [ ] T005 [P] Unit test late fee rule (FR-001) in tests/Billing.Tests/Unit/InvoiceTests.cs
- [ ] T006 [P] Unit test duplicate payment (FR-002) in tests/Billing.Tests/Unit/InvoiceTests.cs

## Phase 3.3: Core Implementation (ONLY after tests are failing)
- [ ] T007 Implement Invoice.Pay in src/Billing/Invoice.cs
- [ ] T008 Implement POST /api/invoices/{id}/payments endpoint

O documento de filosofia do Spec Kit também descreve uma ordem de criação dos testes: contrato, integração, ponta a ponta e unidade. Na prática, isso garante que o agente pense primeiro nas fronteiras do sistema e depois nos detalhes de cada classe.

As tarefas marcadas com [P] podem rodar em paralelo, porque tocam arquivos diferentes. Já a fase de implementação só começa quando todos os testes da fase anterior estão escritos e falhando.

Dos cenários aos testes que falham

Com as tarefas definidas, o agente escreve os testes de unidade a partir dos cenários da spec. O exemplo usa xUnit no .NET 10, a versão LTS atual, e cada teste referencia o requisito que valida.

using Billing;

namespace Billing.Tests.Unit;

public class InvoiceTests
{
    // FR-001: multa de 2% quando o pagamento ocorre após o vencimento
    [Fact]
    public void Pay_AfterDueDate_AppliesTwoPercentLateFee()
    {
        var invoice = new Invoice(amount: 100m, dueDate: new DateOnly(2026, 10, 10));

        var payment = invoice.Pay(paidOn: new DateOnly(2026, 10, 15));

        Assert.Equal(102m, payment.Total);
    }

    // FR-002: uma fatura paga não aceita novo pagamento
    [Fact]
    public void Pay_WhenAlreadyPaid_ThrowsInvalidOperationException()
    {
        var invoice = new Invoice(amount: 100m, dueDate: new DateOnly(2026, 10, 10));
        invoice.Pay(paidOn: new DateOnly(2026, 10, 5));

        var exception = Assert.Throws<InvalidOperationException>(
            () => invoice.Pay(paidOn: new DateOnly(2026, 10, 6)));

        Assert.Equal("Invoice already paid", exception.Message);
    }
}

Para os testes compilarem, o agente cria apenas o esqueleto do domínio, sem nenhuma regra. Esse esqueleto garante a fase vermelha do ciclo, porque todos os testes falham com NotImplementedException.

namespace Billing;

// Esqueleto mínimo: compila, mas ainda não implementa nenhuma regra da spec
public sealed class Invoice(decimal amount, DateOnly dueDate)
{
    public decimal Amount { get; } = amount;
    public DateOnly DueDate { get; } = dueDate;

    public Payment Pay(DateOnly paidOn) => throw new NotImplementedException();
}

public sealed record Payment(decimal Total, DateOnly PaidOn);

Nesse ponto, a suíte do TDD derivada do SDD existe por completo e ainda não há implementação. Então, você revisa os testes, confirma que eles representam a spec e só depois libera o agente para implementar.

A partir daí, o agente segue o ciclo clássico. Ele implementa o mínimo para cada teste passar, roda a suíte e refatora com a garantia de que o comportamento combinado continua intacto.

Revisão humana: onde SDD e TDD se encontram

Gerar testes automaticamente não significa aceitar testes automaticamente. Na combinação de SDD e TDD, a revisão humana muda de lugar e fica mais barata.

Em vez de revisar centenas de linhas de implementação, você revisa a spec e os testes que derivam dela. Esses artefatos são menores, falam a língua do negócio e mostram rapidamente quando o agente entendeu algo errado.

A constitution de exemplo do Spec Kit deixa isso explícito ao exigir que o usuário valide e aprove os testes antes da fase vermelha. Esse portão de aprovação é o momento em que SDD e TDD realmente se encontram.

Durante essa revisão, vale observar alguns sinais objetivos:

  • Todo requisito funcional da spec tem pelo menos um teste associado.
  • Nenhum teste verifica um detalhe de implementação que a spec não exige.
  • Os casos de borda descritos na spec também aparecem como testes explícitos.
  • O nome de cada teste descreve um comportamento, e não um método interno.

Se quiser medir esse comportamento do agente de forma estruturada, vale conhecer o conceito de agent experience e como avaliar agentes de código. Afinal, um agente que gera bons testes a partir da spec é um agente que entendeu a intenção.

Riscos ao combinar SDD e TDD com agentes

A combinação de SDD e TDD resolve muitos problemas, mas traz riscos próprios. O primeiro é o drift, quando o código evolui e a especificação fica para trás.

Nesse caso, os testes continuam passando, porém validam um comportamento que já não corresponde à spec. Por isso, toda mudança de regra precisa começar na especificação e descer até os testes, nunca o contrário.

Outro risco é o excesso de cerimônia em mudanças pequenas. Um ajuste de texto ou uma correção trivial não justifica o fluxo completo, e forçar esse caminho nesses casos só gera atrito no time.

Há também o risco do teste tautológico. Quando o agente escreve um teste que apenas repete a lógica da implementação, a suíte passa sem verificar nada relevante.

Por fim, existe a falsa sensação de cobertura. Uma suíte grande, gerada em segundos, impressiona, mas só tem valor quando cada teste aponta para um requisito real da spec.

Como adotar SDD e TDD no seu time

Adotar SDD e TDD juntos não exige uma reforma completa no processo. Na verdade, o caminho mais seguro é incremental e começa por uma funcionalidade nova, de risco moderado.

  1. Escreva a constitution com o princípio de testes primeiro e com as restrições que valem para todo o projeto.
  2. Gere a especificação da funcionalidade e resolva todas as marcações de dúvida antes de seguir.
  3. Peça ao agente o plano, os contratos e a lista de tarefas, conferindo se os testes vêm antes da implementação.
  4. Revise os testes gerados contra a spec e confirme que todos falham pelo motivo certo.
  5. Libere a implementação e acompanhe o ciclo até a suíte inteira ficar verde.

Depois da primeira funcionalidade, compare o resultado com uma entrega feita sem esse fluxo. Em geral, o retrabalho cai porque as dúvidas aparecem na spec, e não na revisão do pull request.

Além disso, mantenha a spec e os testes no mesmo pull request do código. Assim, quem revisa enxerga a intenção, a prova e a implementação em um único lugar.

Com o tempo, a constitution acumula as lições do time. Cada incidente em produção vira uma nova restrição, e cada nova restrição vira um teste que o agente precisa respeitar dali em diante.

Conclusão sobre SDD e TDD

O debate entre SDD e TDD perde força quando você enxerga o escopo de cada abordagem. O TDD valida unidades e contratos locais no código, enquanto o SDD define intenção, comportamento sistêmico e restrições operacionais para o agente.

Em um mundo de desenvolvimento por agentes, o SDD não substitui o TDD, ele o antecipa. A especificação gera os critérios, os critérios geram as tarefas e as tarefas geram uma suíte que falha antes da primeira linha de implementação.

Com isso, o desenvolvedor sai da posição de quem digita código e assume a posição de quem define e valida a verdade do sistema. Os testes continuam sendo a prova executável, só que agora derivam de uma intenção escrita, revisada e versionada.

Portanto, se você já pratica TDD, o próximo passo é escrever specs melhores. Se você já adotou SDD, garanta que a sua constitution exige testes primeiro, porque é essa regra que transforma intenção em código confiável.

FAQ

O SDD substitui o TDD?

Não, porque as duas abordagens atuam em níveis diferentes. O SDD define o que o sistema precisa fazer, enquanto o TDD prova no código que cada unidade cumpre essa definição.

Preciso do Spec Kit para combinar SDD e TDD?

Não, o Spec Kit é apenas a ferramenta mais conhecida para isso. Qualquer fluxo que transforme uma especificação versionada em testes antes da implementação segue a mesma ideia.

O agente pode escrever os testes e o código na mesma sessão?

Pode, desde que os testes nasçam da spec e você os aprove antes da implementação. O problema surge quando o agente escreve o código primeiro e testa apenas o que implementou.

Qual a diferença entre SDD, TDD e BDD?

O SDD trabalha no nível da funcionalidade, o BDD descreve comportamentos em linguagem comum e o TDD verifica unidades de código. Na prática, o BDD costuma emprestar o formato Given, When, Then aos critérios de aceitação da spec.

Vale usar SDD e TDD em mudanças pequenas?

Nem sempre, porque correções triviais não justificam o fluxo completo. Para essas mudanças, um teste de regressão e uma atualização pontual da spec costumam bastar.