Dossiê Khorikov: Abordagem test-first vs test-last

William Santos - Jan 24 '22 - - Dev Community

Olá!

Este é um post da seção Dossiê Khorikov, onde pretendo traduzir artigos e newsletters de Vladimir Khorikov para o português.

Antes de começarmos, um disclaimer: todas as traduções desta seção foram previamente autorizadas pelo próprio Vladimir Khorikov. Não há qualquer violação de propriedade intelectual neste processo!

Ao mesmo tempo, as traduções não necessariamente refletem minha opinião sobre os temas abordados. São apenas uma fonte de informação adicional aos meus posts -- embora eu seja muito simpático às suas ideias na maioria das vezes!

Por fim, esta é uma tradução da newsletter de 24 de janeiro de 2022, e trata brevemente das abordagens test-first e test-last quando empregando testes em seus projetos.

Vamos lá!


Hoje eu gostaria de tratar do tópico sobre quando escrever testes: antes ou depois do código de produção.

1. Abordagem test-last (teste por último)

A abordagem test-last é a mais comum à qual aderimos e, também, a forma mais intuitiva de escrever testes.

Basicamente, você escreve a aplicação primeiro e, então, a cobre com testes. Nada muito complicado por aqui, este é o modo padrão de desenvolver software.

2. Abordagem test-first (teste primeiro)

A abordagem test-first é o oposto: primeiro você escreve um teste para a funcionalidade que está prestes a desenvolver e, em seguida, escreve a funcionalidade propriamente dita.

A seguir temos o processo TDD em um diagrama:

Image description

  • Escreva um teste que falhe: primeiro você descreve os requisitos para a funcionalidade que será desenvolvida e as expressa como asserções em seu teste.

  • Garanta que o teste falha por um bom motivo: em seguida, você precisa se certificar de que o teste falha porque os requisitos não foram implementados. Desenvolvedores frequentemente pulam esta etapa, mas ela é crucial. O teste precisa falhar por questões relativas à funcionalidade testada, não por questões não relacionadas, como uma exceção que abranja toda a aplicação.

  • Faça o teste passar: nesta etapa você está implementando de fato a funcionalidade que o teste cobre. Neste ponto a qualidade do código não é importante -- o objetivo é fazer o teste passar.

  • Refatore: se o código da etapa anterior estiver bagunçado, organize-o. A razão pela qual esta etapa se separa da anterior é que é muito mais fácil limpar um código pronto e bagunçado que escrevê-lo limpo desde o começo.

3. Test-first vs test-last

Acredite, ou não, as duas abordagens possuem vantagens e desvantagens. Vamos discutir as vantagens de cada uma e ver como você pode usar ambas ao máximo.

3.1. Vantagens do TDD

Então, qual o propósito do TDD? Por quê você adotaria um processo tão complicado?

Ao escrever testes você está constantemente lidando com um problema que é melhor descrito como "quem julga o juíz?"

Seus testes verificam o código da aplicação mas, quem verifica os testes? Como ter certeza de que seus testes validam a funcionalidade em vez de não fazer nada útil?

Este é o problema que o TDD resolve!

Ver o teste falhar pela falta de implementação da funcionalidade, ou por uma implementação incorreta, já o valida. Você sabe que, se o código da aplicação deixar de funcionar corretamente, o teste indicará isso.

Em outras palavras, esta abordagem reduz o risco de falsos negativos. Você já viu o teste falhar e pode esperar que ele se comporte da mesma forma posteriormente.

Esta é a razão pela qual o passo 2 (garantir que o teste falhe por um bom motivo) é tão importante. Se o teste falhar por uma razão não associada à funcionalidade (digamos, se a seção de preparação do teste não foi configurada corretamente), você não estará validando o teste, e não tem como saber se, caso ele falhe, será por uma quebra na funcionalidade.

Com a abordagem test-last você precisa realizar esta validação manualmente: mudar o código da aplicação para simular um bug, garantir que o teste quebre e, então, reverter o código da aplicação. Isso é cansativo e muita gente simplesmente pula esta etapa, o que pode resultar em testes incorretos.

TDD é ótimo porque esta etapa de validação é realizada durante o próprio processo de escrita, e você não tem qualquer trabalho adicional.

3.2 Vantagens da abordagem test-last

Sendo assim, qual a vantagem em escrever o código da aplicação primeiro?

Flexibilidade!

Uma vez que você não precise se preocupar com os testes de antemão, você pode alterá-lo facilmente, refatorando-o ou até mesmo reescrevendo-o.

Com testes a priori, é mais difícil fazer esse tipo de mudança, porque você precisaria ajustar os testes após cada uma.

3.3 Quando usar cada abordagem

Ambas as abordagens tem suas vantagens e você pode aplicá-las no estágio certo em seu projeto.

Esses estágios podem ser divididos em 2 categorias:

  • Fazer a coisa certa
  • Fazer direito

Ou seja, primeiro você precisa descrever o escopo do projeto, para ter certeza de que sua solução é a correta e, só então, construir esta solução.

O primeiro estágio envolve experimentação, rascunho do seu modelo de domínio, sessões no quadro branco etc. Você não precisa dos testes neste momento: eles apenas vão te atrasar e há uma boa chance de você ter de descartá-los junto com o código que está experimentando.

Uma vez que você tenha certeza da solução, você pode prosseguir para o segundo estágio: fazer direito. É aqui que você pode seguir o TDD e obter todos os seus ganhos de longo prazo, como uma boa cobertura e testes de qualidade.

O problema com o TDD é que, de forma a ser produtivo, você precisa saber exatamente o que está construindo. Entretanto, tão logo você saiba, você pode se beneficiar muito desta abordagem.

Um outro campo onde o TDD brilha é na correção de bugs. Se você encontra um bug, não o corrija de imediato. Primeiro, escreva um teste que o reproduza, garanta que ele falhe e, então, corrija-o. Desta forma você nunca mais vai precisar se preocupar com aquele bug novamente.

--Vlad.


Gostou? Me deixe saber pelos indicadores. Se quiser, deixe um comentário ou me procure em minhas redes sociais.

Até a próxima!

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .