5 passos do Desenvolvimento Orientado a Testes (TDD)

6 min de leitura
Patrocinado
Imagem de: 5 passos do Desenvolvimento Orientado a Testes (TDD)
Avatar do autor

Equipe TecMundo

@tec_mundo

Neste artigo, são apresentados os conceitos básicos de Desenvolvimento Orientado a Testes (em inglês, test-driven development – TDD). Caso você seja um desenvolvedor e utilize os métodos ágeis (Agile Development), o TDD é a melhor prática a ser incluída no ciclo de vida de sua solução. Entenda o que é Desenvolvimento Orientado a Testes, conheça o fluxo básico envolvido e descubra como testes unitários são os pilares da metodologia. Ao fim da leitura, você terá compreendido por que é indicado utilizar Desenvolvimento Orientado a Testes em seus processos.

O que é Desenvolvimento Orientado a Testes (TDD)?

Desenvolvimento Orientado a Testes é um processo que modifica o paradigma do desenvolvimento de softwares tradicional. Em vez de desenvolver, primeiramente, seu código e ajustá-lo de maneira retroativa para validá-lo, o TDD determina que os testes sejam escritos antes e que as adaptações sejam, só depois, aplicadas ao código até que o projeto atenda aos requisitos do teste já definido.

No TDD, você escreve o teste unitário antes, observa as falhas e então implementa as alterações necessárias até que não falhe mais. Parece o inverso do normal, certo? Entretanto, o código que você produz quando utiliza essa metodologia é mais limpo e menos propenso a falhar em longo prazo.

Um teste unitário cobre apenas uma pequena porção da lógica, como funções ou métodos. Testes unitários devem ser determinísticos, ou seja, não devem apresentar efeitos colaterais, como chamadas para APIs externas que forneçam dados aleatórios ou variáveis. Em vez disso, são utilizados dados simulados, substituindo aqueles que poderiam ser alterados depois de um tempo.

5 passos do Desenvolvimento Orientado a Testes (TDD)

1 – Leia, entenda e analise o recurso a ser implementado ou a indicação de erro.

2 – Traduza a requisição necessária escrevendo um teste unitário. Importante: se existir configuração de hot reload, o teste unitário vai rodar e falhar como se código algum houvesse sido implementado.

3 – Escreva e implemente o código que preenche a solicitação. Rode todos os testes. Caso funcionem, está tudo certo. Se não, repita o processo.

4 – Limpe seu código por meio da refatoração.

5 – Volte ao passo 1 e faça tudo novamente.

A Figura 1 apresenta esses passos e sua natureza ágil, cíclica e iterativa:

Figura 1

O fluxo de trabalho do TDD é chamado frequentemente de Red-Green-Refactoring (Vermelho-Verde-Refatoração), apresentando o status dos testes dentro de cada círculo.

– A etapa vermelha indica que o código não funciona.

– A etapa verde indica que tudo está funcionando, mas não necessariamente de maneira otimizada.

– A etapa azul indica que o responsável pelo teste está refatorando o código; confiante de que o código passou por vários testes, altera e aprimora o que chegou a ele com mais segurança.

Desenvolvimento Orientado a Testes e CI/CD

Testes unitários derivados do TDD também fazem parte do processo de integração e entrega contínuas (CI/CD). TDD diz respeito especificamente a testes unitários e pipelines CI/CD, como CircleCI, GoCD ou Travis CI, que executam todos os testes unitários no momento de registro de alterações realizadas.

Os testes são executados no pipeline de deploy. Caso todos sejam bem-sucedidos, a integração e a implementação acontecerão. Por outro lado, caso algum falhe, o processo é interrompido, garantindo, assim, que a build não seja prejudicada mais à frente.

Integração contínua (CI) é a prática de desenvolvimento que leva desenvolvedores a integrarem códigos diversas vezes ao dia a um repositório compartilhado. Cada entrada é verificada por uma build automatizada, permitindo que o time responsável pelo projeto detecte problemas precocemente. Com a integração regular, é possível verificar falhas rapidamente e localizá-las com mais facilidade.

Ferramentas, toolchain e Ambiente de Desenvolvimento Integrado (IDE) indicados

Para produzir seu TDD, você precisará definir quais ferramentas, toolchain e Ambiente de Desenvolvimento Integrado (IDE) serão utilizados nos processos. Em nosso [padrão de código], estamos desenvolvendo um Node.js como exemplo. Estas foram as ferramentas básicas que selecionamos:

– nvm (Node Version Manager) for Node.js and NPM: NVM permite a você executar a versão Node.js desejada e alterá-la sem afetar o node system.

– Bibliotecas npm para desenvolvimento: 

  •    Jest para testes unitários
  •    ESLint para executar lint
  •    Prettier para formatação do código
  •     Husky e lint-staged para o pré-commit dos Git hooks

Como escrever testes unitários quem falhem 

Há duas maneiras de criar testes unitários que falhem. 

1 – Escreva um teste que tenha relação com uma função de um código que não exista ainda. Isso vai fazer com que o teste falhe e indique um erro relacionado a uma função não encontrada (por exemplo, o Erro 404).

2 – Altere o statement do assert com o intuito de falhar. Ele é que determina o retorno esperado do código testado, sendo um aspecto-chave do teste unitário. O statement do assert deve estar relacionado com a função ou a solicitação de correção de bug. 

Então, com o intuito de falhar, você deve escrever um statement de assert que retorne um valor inesperado em uma estrutura de dados que você deseja aprimorar. Por exemplo, seu JSON foi desenvolvido para fornecer o nome de uma pessoa, mas a nova implementação especifica o retorno do número de telefone dela. No teste, você primeiro escreveria um assert para incluir apenas o nome, o que apresentaria erro. Então, você adicionaria o código para incluir o número de telefone também.

Veja o funcionamento na aplicação do código em si:

Seu statement do assert poderia ser:

assert actualResult == {‘track’:‘foo fighters’}

Assim que a função é submetida, o Erro 404 desaparece, mas o resultado final poderia ser um objeto vazio, como {}. Logo, você deve lapidar o resultado na função do código para:

 {‘track’:‘foo fighters’}

Agora o teste será bem-sucedido (verde). O código é obviamente apenas um elemento abordado por enquanto, mas, a partir disso, é possível entender os elementos básicos do processo. O teste está aplicado corretamente até certo ponto. Depois disso, você pode implementar a lógica efetivamente, podendo, por exemplo, analisar um file/db/call em uma API externa.

Quando escrever testes unitários?

No geral, há duas situações em que é aconselhado escrever testes unitários:

Situação A: para uma história concisa que exemplifique a implementação de um recurso. Por exemplo, um recurso poderia ser a contagem do número de países atendidos por uma determinada casa de câmbio. A primeira coisa a se fazer é escrever um teste e verificar as falhas. Depois, o código deve ser alterado iterativamente até que os testes sejam bem-sucedidos.

Situação B: uma parte de código “bugado” em desenvolvimento “quebra”, exigindo a implementação de uma correção. Voltando ao exemplo da casa de câmbio, o usuário espera que o código, quando executado manualmente, retorne um grande número de países que utilizem o dólar como moeda, mas o resultado traz apenas um país.

A primeira coisa a se fazer é escrever um teste e vê-lo falhar. Então, as correções devem ser implementadas até que o teste seja bem-sucedido. Isso não apenas corrige o código e remove o bug, como também oferece um teste unitário que pode ser utilizado repetidamente para manter a integridade do código como um todo.

Conclusão

A maioria dos programadores não escreve códigos utilizando o Desenvolvimento Orientado a Testes, mas deveria. O desenvolvimento orientado a testes cria um código melhor e menos propenso a falhas. Por isso, esperamos que tenha entendido a filosofia do TDD com este texto e a incorpore nas suas práticas de desenvolvimento.

Próximos passos

Fique atento a novos posts sobre como efetuar desenvolvimento orientado a testes em Node.js, Java e Python.

Recursos

Frameworks de testes unitários recomendados

  • Pytest: ferramenta open source intuitiva para facilitar a condução de testes unitários
  • Java: Junit 5: framework amigável de testes para Java
  • NodeJS: Jest: framework de testes para JavaScript com foco em simplicidade

Livros e artigos úteis

...

Quer ler mais conteúdo especializado de programação? Conheça a IBM Blue Profile e tenha acesso a matérias exclusivas, novas jornadas de conhecimento e testes personalizados. Confira agora mesmo, consiga as badges e dê um upgrade na sua carreira!

5 passos do Desenvolvimento Orientado a Testes (TDD)