
Uma campanha oferece desconto de 10%, mas ninguém decidiu se o valor mínimo inclui o próprio limite, se há teto ou como tratar frações de centavo. Você começa criando classes de campanha e cupom. Quando chega ao primeiro teste, já tomou várias decisões que o requisito não sustentava.
Test-Driven Development: By Example, de Kent Beck, merece leitura porque desloca a atenção para o próximo comportamento verificável. Minha recomendação é estudá-lo como prática de decisão e feedback: formular uma expectativa, confrontá-la com execução e reorganizar o código quando houver base para isso. Essa disciplina continua útil sem transformar todo problema em exercício de teste unitário.
Esta resenha considera a primeira edição. A ficha da Addison-Wesley/Pearson registra publicação em 8 de novembro de 2002 e copyright de 2003. A estrutura contém um exemplo de dinheiro em múltiplas moedas, a construção de um framework xUnit e uma seção de padrões de TDD.
Minha sugestão é acompanhar a sequência das decisões, em vez de tentar reaproveitar as implementações. Pergunte qual dúvida cada exemplo resolve e se o próximo passo seria igualmente claro no seu projeto. Essa comparação torna a leitura ativa.
Comece com uma lista de cenários; transforme um deles em teste executável, faça esse teste e os anteriores passarem, depois avalie refatorar. Beck esclarece essa sequência em Canon TDD, publicado em 2023. A lista pode crescer enquanto você descobre perguntas novas.
Minha aplicação dessa orientação é separar três perguntas. O vermelho mostra que falta o comportamento pretendido? O verde resolve o caso sem esconder a falha? A refatoração conserva o contrato enquanto melhora a estrutura? Observar um erro de importação não demonstra que o teste detecta um desconto incorreto. É preciso chegar à falha relevante.
Um caso que já nasce verde ainda pode documentar um requisito ou revelar uma lacuna na sua hipótese sobre o código. Entretanto, não registra a mesma evidência de uma implementação que falhava e passou a funcionar. Inspecione por que passou; não altere a expectativa apenas para fabricar uma sequência visual de cores.
Para o cupom fictício desta resenha, defina primeiro o contrato: subtotal em centavos inteiros não negativos; cupom ativo a partir de 2.000 centavos; desconto de 10%, limitado a 500 centavos. A divisão inteira descarta frações de centavo. São decisões didáticas deste exercício, que precisariam de validação do negócio em um produto real.
Essa definição suscita perguntas úteis. O subtotal já inclui outros descontos? A promoção vale para impostos? Uma devolução pode produzir valor negativo? Aqui essas questões ficam fora da função, com o subtotal inválido rejeitado. A explicitação do limite é mais honesta que adicionar parâmetros especulativos para regras ainda desconhecidas.
Escolha casos que obriguem decisões distintas. Um subtotal abaixo do mínimo pergunta sobre elegibilidade. O valor exato de 2.000 pergunta sobre inclusão do limite. Um valor maior pergunta sobre cálculo; outro exige o teto. Cupom inativo pergunta sobre habilitação. Repetir exemplos que exercitam o mesmo caminho pode aumentar a suíte sem esclarecer a próxima decisão.
No capítulo disponibilizado como Equality for All, Beck mostra uma implementação temporária constante e a triangulação: outro exemplo pode exigir uma solução mais geral. Ele também explica que usa triangulação quando a direção da generalização está incerta.
No nosso caso, retornar zero passa o primeiro teste abaixo do mínimo. O cenário exatamente no limite exige 200, então a constante deixa de bastar. Esse contraste torna a necessidade da regra visível. Se a implementação já está clara, escrevê-la diretamente pode ser uma escolha melhor que encenar passos minúsculos.
O critério é conseguir explicar o que cada passo revelou. Se você se perde em uma condição, diminua a mudança. Se conhece a operação, pode avançar mantendo os testes. Uma constante provisória precisa desaparecer quando o contrato exige variação; deixá-la cercada de exceções para cada entrada seria memorizar exemplos em vez de implementar a regra.
Produtos gratuitos e pagos para transformar ideias em uma base que você consegue executar.
13 produtos disponíveisContinue explorando tópicos similares

Resenha de Refactoring, segunda edição: passos pequenos, testes e contratos, com exemplo executável, críticas e um roteiro de aplicação.

Use Michael Feathers para começar uma mudança em código sem testes, localizar dependências e registrar o comportamento existente.

Aplique Michael Nygard a timeouts, isolamento e recuperação com um exercício de falha controlada.
Checklist de 47 pontos para encontrar bugs, riscos de segurança e problemas de performance antes do lançamento.
Templates testados em produção, usados por desenvolvedores. Economize semanas de setup no seu próximo projeto.
O bloco abaixo é original e representa o estado final verde, não uma demonstração de todos os estados intermediários. Requer Python 3 e apenas biblioteca padrão. Salve como coupon_tdd.py e execute python3 coupon_tdd.py, sem a opção -O, que desativa assertions.
def discount_cents(subtotal_cents: int, coupon_active: bool) -> int:
if type(subtotal_cents) is not int or subtotal_cents < 0:
raise ValueError("subtotal must be non-negative integer cents")
if not coupon_active or subtotal_cents < 2000:
return 0
return min(500, subtotal_cents // 10)
cases = [
(1000, True, 0),
(2000, True, 200),
(3000, True, 300),
(9000, True, 500),
(3000, False, 0),
(2009, True, 200),
]
for subtotal, active, expected in cases:
assert discount_cents(subtotal, active) == expected
for invalid in (-1, 1.5, True):
try:
discount_cents(invalid, True)
except ValueError:
pass
else:
raise AssertionError(f"accepted invalid subtotal: {invalid!r}")
print("6 discount cases and 3 invalid inputs passed")
Saída esperada:
6 discount cases and 3 invalid inputs passed
O caso de 2.009 centavos verifica o descarte da fração. A validação rejeita True como subtotal porque booleanos são uma subclasse de inteiros em Python. O argumento coupon_active tem como pré-condição receber um booleano; esta função não valida dados de HTTP. O adaptador de entrada precisa estabelecer esse contrato.
Para reconstruir o desenvolvimento, mantenha inicialmente apenas o primeiro caso, implemente zero e acrescente o segundo. Veja a expectativa de 200 falhar antes de introduzir elegibilidade e cálculo. Depois acrescente teto, habilitação, fração e entradas inválidas, um comportamento por vez. O bloco completo já passa e, sozinho, não comprova que seu processo seguiu TDD.
O cálculo usa subtotal e habilitação; não precisa de carrinho persistido ou cliente de pagamentos. Essa fronteira torna o teste barato e deixa o contrato legível. Se você precisa criar uma conta, consultar estoque e autenticar uma sessão para calcular desconto, investigue onde decisões comerciais ficaram presas a detalhes de transporte.
Isso não autoriza criar uma interface para cada operação. Na função acima não há mocks, hierarquia ou framework. Acrescentar camadas sem um problema concreto pioraria o exemplo. O design melhora quando torna as dependências necessárias explícitas e reduz o trabalho para entender uma mudança.
Também prefira expectativas sobre resultados a expectativas sobre toda chamada interna. Trocar o cálculo por uma expressão equivalente deveria preservar os casos. Já uma ordem de efeitos realmente contratual, como persistir uma reserva antes de publicar sua confirmação, merece teste específico e explicação do motivo.
Um erro na regra compartilhado por implementação e expectativa pode passar despercebido. Se marketing entende o limite como 2.500 centavos e você escreve 2.000 nos dois lados, a suíte fica verde. Exemplos aprovados por quem entende a promoção fornecem uma verificação diferente da consistência entre seus próprios artefatos.
O exemplo também ignora concorrência. Dois pedidos podem tentar consumir a última utilização de um cupom ao mesmo tempo. A função pura não protege contador, transação ou unicidade. Um teste unitário do desconto deve coexistir com testes da política de consumo e evidência sobre como o armazenamento resolve a disputa.
Integrações acrescentam limites próprios: o provedor pode arredondar de outra forma ou rejeitar uma combinação de descontos. Testes de contrato e integração precisam observar esses acordos. A leitura de Beck ajuda a pensar no próximo comportamento, mas não substitui experimentos de segurança, análise de falhas nem validação com usuários.
O ponto forte é tornar pequenas decisões discutíveis. Você consegue perguntar por que escolher determinado teste, por que generalizar naquele momento e por que adiar uma abstração. Para estudo em dupla, essa visibilidade rende mais que discutir TDD apenas como preferência pessoal.
Os exemplos são delimitados. Eles não incluem a negociação de uma regra ambígua com várias equipes nem o custo de tornar um sistema antigo testável. Quem espera uma receita que descubra automaticamente uma boa arquitetura pode sair com confiança excessiva. A escolha da fronteira do teste continua exigindo conhecimento do sistema.
O ritmo também exige adaptação. Reproduzir cada passo mecanicamente pode parecer lento e não transferir aprendizado para seu projeto. O exercício importante é explicar quando reduzir o passo e quando uma implementação direta é suficiente. Quantidade de testes e frequência de execução não compensam expectativas frágeis ou uma fronteira inadequada.
Recomendo para desenvolvedores que conhecem funções ou objetos e já escreveram assertions. Um iniciante pode estudar junto de exercícios pequenos, mas não precisa aprender programação, modelagem e ferramentas de testes simultaneamente. Quem ainda tem dificuldade para executar uma função isolada pode consolidar essa base primeiro.
Para uma base sem proteção, Working Effectively with Legacy Code ajuda a obter uma entrada observável. Seus testes de caracterização descobrem comportamento existente; aqui o cupom parte de expectativas desejadas. Confundir esses objetivos leva a copiar resultados atuais como se fossem requisitos novos.
Refactoring complementa o momento de melhorar estrutura preservando comportamento. Em uma equipe com suíte lenta ou instável, reserve trabalho para seu ambiente de feedback. Ler Beck não torna rápidas consultas remotas nem corrige fixtures compartilhadas.
Use uma sessão curta para reconstruir o cupom e registrar a ordem dos casos. Em outra sessão, eleve o mínimo de 2.000 para 2.500 centavos. O caso (2000, True, 200) deve acusar a mudança na implementação antes de sua expectativa ser deliberadamente atualizada para zero. Acrescente os casos de 2.499 e 2.500, especificando seus resultados pela nova regra. Observe se a mudança obriga a reconstruir dependências desnecessárias.
Depois aplique o ciclo a uma regra pequena do trabalho, com revisão de um colega. Anote perguntas de domínio descobertas, mudanças estruturais e verificações que ficaram fora dos testes locais. Avalie a qualidade dessas decisões, sem inventar metas de produtividade a partir de um exercício.
Recomendo o livro para aprender a transformar dúvida em uma próxima verificação concreta. O retorno esperado é controle sobre o tamanho das decisões e sobre a evidência disponível. Você aproveitou a leitura quando consegue escolher um caso que esclarece o contrato e explicar, mesmo com a suíte verde, quais riscos continuam abertos.