Aguarde...

15 de julho de 2019

Desenvolvimento Orientado a Testes RIP

Desenvolvimento Orientado a Testes RIP

Ou estamos apenas pensando sobre isso errado? A filosofia central por trás do TDD

Há um equívoco sobre o que realmente é o desenvolvimento orientado a testes. Todos nós sabemos o que é, mas, ao mesmo tempo, não sabemos realmente.

Geralmente é a palavra ‘teste’ que nos joga fora. Então acabamos escrevendo unidades de teste longas e complicadas, às vezes o código de teste sendo mais do que o próprio código em si. É tudo divertido e jogos na primeira iteração, mas se algo precisa ser mudado, então a refatoração massiva das unidades de teste é necessária antes que você possa fazer qualquer coisa em particular. Este é frequentemente o primeiro sinal de que o TDD foi implementado incorretamente.

Na terceira rodada, nós, desenvolvedores, simplesmente jogamos nossas mãos para testar nosso código e decidimos simplesmente agilizar. Nós entramos em colapso sob o peso dos testes que deveriam nos poupar tempo e garantir a robustez do nosso produto final.

“RIP TDD” nós sussurramos, então nunca mais falamos sobre isso.

Mas o desenvolvimento orientado para testes não é tão ruim assim, é apenas mal entendido.

Colidindo com a ideia por trás do TDD

O que muitos de nós tendem a fazer quando nos deparamos com a programação orientada por testes é que escrevemos testes para todos os métodos e classes possíveis. Isso geralmente causa um problema, se esses métodos se tornarem redundantes ou precisarem ser alterados.

Isso não é TDD. Isso é uma abstração excessiva do que o TDD deveria ser.

“O código que comunica seu propósito é muito importante”.

– Martin Fowler, Refatoração: Melhorando o Design do Código Existente

O objetivo de qualquer software é alcançar um resultado final específico, com contingências quando as coisas não acontecem como deveriam. São cenários gerados e consumidos pelo usuário final. Para o backend, esse usuário final é o frontend. Para o frontend, o usuário final é o cliente.

Quando o software é testado, isso significa que o fluxo de trabalho de desenvolvimento está focado em produzir um conjunto de resultados específicos que emulem as necessidades de seus consumidores. Trata-se de preencher os requisitos – não criando requisitos sobre como estruturar e produzir seu código. Quando você faz o último, sua suíte de testes é frágil para mudar.

Mas nós não queremos isso. Queremos testes que sejam capazes de resistir a mudanças, pois queremos que o software não seja quebrado se precisarmos fazer uma alteração. Supõe-se que os testes indiquem quão robusto é nosso código, e não o quanto está fortemente acoplado às unidades de teste.

Na sua forma mais simples, o TDD adequado é uma abstração dos requisitos do usuário. Mas o que isso significa?

A linguagem do TDD

O objetivo do software é o cumprimento de um conjunto específico de requisitos. Muitas vezes esquecemos esse propósito fundamental quando escrevemos nossas unidades de teste.

O objetivo do código é traduzir esses requisitos em uma linguagem que é posteriormente traduzida em bits e bytes. Código é a ponta do ice berg que queremos esculpir em algo claro e compreensível para outros desenvolvedores. O desenvolvimento orientado a testes cria o suporte para o que queremos que o resultado final seja semelhante.

Isso significa escrever testes de uma forma que comunique isso na linguagem humana normal.

teste se x será retornado quando aeb são adicionados juntos

O idioma acima não é útil para ninguém, a menos que você esteja construindo uma calculadora. Mas esse tipo de linguagem está presente em vários códigos de teste que visam especificamente os métodos e, portanto, o acoplam a uma determinada classe.

testar se itens são adicionados ao carrinho quando acionados

Esse teste é muito mais rico em informações e fornece o formato dos dados. Ele não olha como as coisas são implementadas, mas apenas se preocupa com a entrada e saída finais.

itemstem que ter uma certa forma cartpara funcionar. Em contraste com o primeiro teste, isso é muito mais robusto porque, a menos que os requisitos para o que itemsparece ser alterado, o teste em si não precisa ser alterado.

O código sob o capô, no entanto, é fluido e tem escopo para os limites do teste.

testar se a confirmação modal aparece quando o botão enviar é clicado

Este caso de teste é voltado para um software voltado para frontend. O teste acima não importa como você chegou lá, só que você chegou lá. Isso faz com que seja um caso de teste flexível para implementar, já que qualquer alteração nos bastidores não interromperá as suítes de teste.

Mas isso não é apenas trapaça? Não deveríamos estar testando tudo?

Sim e não.

Ao escrever testes, seus modelos mentais devem ser guiados pela criação de testes que provem que seus requisitos foram atendidos. Testar se uma determinada função funciona ou não precisa ser avaliada em como ela se encaixa no relacionamento com o recurso real em que você está trabalhando.

Se tiver um certo grau de separação, seu teste provavelmente está muito acoplado ao código real.

Sua unidade de teste não deve determinar quais tipos de padrões usar ou qual deve ser a implementação final. Deve preocupar-se apenas com o resultado final esperado com base em um cenário específico. Um robusto conjunto de testes é uma coleção de testes que captura a especificação – evita casos de uso. Faz você pensar em exceções e erros, e o que acontecerá se a sequência de eventos ou entrada não for exatamente o esperado.

O problema com o TDD é que muitos novos para testar tendem a abstrair em vez de focar na estrutura. Isso é como martelar as unhas sem ver como tudo deve se juntar. Quando terminar, você poderá perceber que sua base não está certa e voltar à estaca zero e escrever os testes novamente.

No entanto, se você descobrir quais comportamentos esperar, quando e onde, então você é capaz de construir uma imagem maior – tipo de pensamento através de seus testes.

Palavras finais

Pensar em desenvolvimento orientado a testes é como um mecânico testaria um carro. O engenheiro projeta-o, as máquinas da fábrica o constroem, mas seu mecânico local é aquele que passa por uma série de testes para verificar se o carro é digno de uma estrada.

Ele só começa a abstrair os detalhes mais sutis se algo não estiver certo. Se os faróis não estiverem funcionando, ele perguntará que tipo de lâmpada precisa ser substituída. Substituiu a lâmpada e ainda não está funcionando? Talvez seja a fiação. Você começa a essência.

Isto é basicamente TDD – testando para ver se o seu software produz um resultado esperado, de nível superior e claramente especificado.O mecânico não faz as peças, ele só as usa. Como desenvolvedores, precisamos aprender a pensar como o mecânico ao escrever suítes de teste para o TDD.

Então, podemos recolocar nossos chapéus de engenharia e descobrir como são essas peças e como elas devem ser feitas. Se as partes quebrarem facilmente, há um defeito no desenho. O teste apenas detecta o rompimento – não determina e não deve ditar o design.

Esse é basicamente o princípio central por trás do TDD.


Postado em BlogTags:
Escreva um comentário