Leaders Logo

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 define o comportamento esperado do sistema ao descrever de forma explícita suas entradas, saídas, regras de negócio, restrições e cenários excepcionais. Ao atuar como uma fonte única de verdade, ela reduz interpretações subjetivas e fornece uma referência consistente para as atividades de desenvolvimento, testes e validação. Uma especificação bem elaborada é clara, concisa e testável, permitindo que tanto públicos técnicos quanto não técnicos compreendam com precisão o que o software deve realizar (GOLDMAN; ABRAHAM; SONG, 2007).

Por que a especificação é importante?

Na ausência de uma especificação explícita, cada membro da equipe tende a formar sua própria interpretação do problema, o que frequentemente resulta em retrabalho, desalinhamento e inconsistências na implementação. A literatura sobre desenvolvimento orientado por especificação destaca que a formalização prévia do comportamento do sistema é um dos principais mecanismos para mitigar ambiguidades e prevenir erros ainda nas fases iniciais do ciclo de desenvolvimento (FOFUNG, 2015).

Quando a especificação é definida antes da implementação, ela pode ser integrada diretamente ao processo de testes. Estudos mostram que a combinação de especificações formais com práticas como Test-Driven Development (TDD) amplia a cobertura de cenários, melhora a rastreabilidade dos requisitos e gera artefatos de documentação mais precisos, atuando de forma complementar aos testes unitários tradicionais (BAUMEISTER, 2004).

Exemplo Completo de SDD: Da Especificação ao Teste

Fluxo de SDD voltado para testes

A imagem abaixo representa o fluxo do Spec Driven Design (SDD) aplicado ao desenvolvimento orientado por testes, evidenciando como a especificação guia a criação dos testes unitários e, posteriormente, a implementação do código.

Imagem SVG do Artigo

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 discount

func 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:

  1. Especifica-se o comportamento.
  2. Derivam-se os testes unitários.
  3. Implementa-se apenas o necessário para atender aos testes.
  4. 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. 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

  • GOLDMAN, James L.; ABRAHAM, George; SONG, IlYeol. Generating Software Requirements Specification (IEEE Std. 830 1998) document with Use Cases. no, v. 215, p. 1-12, 2007. reference.Description
  • FOFUNG, Titus. Formal Specification Driven Development. 2015. reference.Description
  • BAUMEISTER, Hubert. Combining formal specifications with test driven development. In: Conference on Extreme Programming and Agile Methods. Berlin, Heidelberg: Springer Berlin Heidelberg, 2004. p. 1-12. reference.Description
Sobre o autor