Do Documento ao Código: Testes Unitários Derivados de Spec Driven Design
Introdução
O desenvolvimento de software evoluiu para práticas cada vez mais orientadas à precisão. Entre elas, o Spec Driven Design (SDD) se destaca ao colocar a especificação como peça central do desenvolvimento. Quando combinado com testes unitários, o SDD cria um ciclo robusto: primeiro define-se o comportamento esperado; depois, os testes garantem que a implementação siga exatamente esse contrato. Este artigo apresenta como o Spec Driven Design funciona na prática e como ele guia a criação de testes unitários em C# e Go (Golang).
Especificação como Base do Desenvolvimento
A especificação descreve o comportamento esperado do sistema — entradas, saídas, regras, restrições e exceções. Ela elimina interpretações subjetivas e serve como referência única para desenvolvimento, testes e validação. Segundo Hansen et al. (2015), uma boa especificação é clara, concisa e testável, permitindo que qualquer pessoa, técnica ou não, compreenda o que o software deve fazer.
Por que a especificação é crítica?
Sem especificação, cada membro da equipe cria sua própria interpretação do problema. Isso leva a retrabalho, desalinhamento e inconsistências. Quando a especificação é bem definida antes do desenvolvimento, o time elimina ruídos e acelera entregas — exatamente o que metodologias ágeis procuram: iterar rápido sem perder qualidade.
Exemplo Completo de SDD: Da Especificação ao Teste
A seguir, um exemplo prático de como o Spec Driven Design orienta a construção de testes e código. O caso é simples, mas mostra o processo de ponta a ponta.
Especificação (SDD)
Contexto: módulo de cálculo financeiro.
# Especificação — Regra de Negócio: Cálculo de Desconto Progressivo
## Descrição
O sistema deve aplicar um desconto baseado no valor total da compra.
## Regras
- Se o valor for menor que 100, não aplica desconto.
- Se o valor estiver entre 100 e 500 (inclusive), aplica 5%.
- Se o valor for maior que 500, aplica 10%.
## Fórmula
preco_final = valor - (valor * percentual)
## Casos de Teste Derivados da Especificação
1. valor = 50 ? preco_final = 50
2. valor = 100 ? preco_final = 95
3. valor = 500 ? preco_final = 475
4. valor = 800 ? preco_final = 720
Observe: os testes saem diretamente da especificação. Não há espaço para interpretação. Teste virou contrato.
Testes em C# (derivados da especificação)
using Xunit;public class DiscountService { public decimal Calculate(decimal value) { if (value < 100) return value; if (value <= 500) return value * 0.95m; return value * 0.90m; } }
public class DiscountServiceTests { [Theory] [InlineData(50, 50)] [InlineData(100, 95)] [InlineData(500, 475)] [InlineData(800, 720)] public void Calculate_ShouldApplyCorrectDiscount(decimal input, decimal expected) { var service = new DiscountService(); var result = service.Calculate(input); Assert.Equal(expected, result); } }
Testes em Go (derivados da especificação)
package discountfunc Calculate(value float64) float64 { if value < 100 { return value } if value <= 500 { return value * 0.95 } return value * 0.90 }
package discount_test
import "testing"
import "discount"
func TestCalculate(t *testing.T) {
cases := []struct{
input float64
want float64
}{
{50, 50},
{100, 95},
{500, 475},
{800, 720},
}
for _, c := range cases {
got := discount.Calculate(c.input)
if got != c.want {
t.Errorf("Calculate(%f) = %f; want %f", c.input, got, c.want)
}
}
}
Do Documento ao Código: O Fluxo do Spec Driven Design
No SDD, o processo é direto:
- Especifica-se o comportamento.
- Derivam-se os testes unitários.
- Implementa-se apenas o necessário para atender aos testes.
- Refatora-se com segurança, sabendo que o contrato está protegido.
Esse fluxo reduz ambiguidades e garante que o software final corresponda exatamente às necessidades documentadas.
Por que isso reduz falhas?
Porque a implementação não nasce de “ideias” ou “interpretações”. Ela nasce de regras explícitas. Se o teste falha, a implementação está errada. Se o teste passa, o contrato está atendido. Simples e direto.
Testes Unitários e Qualidade do Código
Testes unitários funcionam como uma rede de proteção evolutiva. Ao modificar o código, o desenvolvedor sabe imediatamente se violou alguma regra da especificação. Em ambientes ágeis — especialmente multiproduto ou com squads simultâneas — essa confiança é obrigatória.
Refatoração sem medo
Refatorar significa melhorar a estrutura interna sem mudar o comportamento externo. Beck (2003) destaca que “testes são a melhor documentação”. Com testes derivados da especificação, a regra fica registrada em código e não se perde com o tempo.
Colaboração e Agilidade
O SDD melhora a comunicação entre desenvolvedores, QA, PO e stakeholders. A especificação vira a fonte única da verdade. Os testes garantem que ela está sendo respeitada. Isso reduz discussões subjetivas e aumenta a velocidade das entregas.
SDD dentro de práticas ágeis
Equipes que seguem SDD conseguem integrar testes automatizados no CI/CD, entregando valor contínuo. Cada mudança dispara a suíte de testes, validando a conformidade com o comportamento esperado.
Desafios e Considerações Finais
Aplicar SDD exige disciplina. A especificação precisa ser atualizada sempre que o comportamento do sistema muda. Além disso, a equipe deve equilibrar cobertura de testes com a complexidade do domínio. Porém, quando usado corretamente, o SDD reduz retrabalho, aumenta a qualidade e deixa o desenvolvimento mais previsível.
Referências
BECK, K. Test Driven Development: By Example. Addison-Wesley, 2003.
HANSEN, J. et al. Improving Software Quality through Specification and Testing. In: Proceedings of the International Conference on Software Engineering. IEEE, 2015.
HUMPHREY, W. S. Managing the Software Process. Addison-Wesley, 1989.
LEFF, A. et al. Spec Driven Development: A New Approach to Software Development. ACM Transactions on Software Engineering and Methodology, 2017.