Antes de chegar à pessoa usuária, um software deve estar funcionando perfeitamente. É por isso que a correção de erros e bugs do sistema é um processo delicado que, geralmente, aumenta o tempo de desenvolvimento. Mas você sabia que existe um método bastante popular que ajuda a evitar esse problema? Sim, ele existe e se chama TDD.

O TDD foi criado para auxiliar no desenvolvimento de códigos mais concisos, com menos dependências e acoplamentos, reduzindo a incidência de erros na aplicação.

Neste guia completo sobre TDD, você vai conhecer:

Boa leitura!

O que significa TDD?

TDD é a sigla em inglês para o método chamado Test-Driven Development. Já no português, o termo pode ser traduzido para Desenvolvimento Orientado a Testes e se refere a uma abordagem de desenvolvimento que trabalha com pequenos ciclos de repetições, nos quais são criados testes para cada nova funcionalidade que será implementada no software.

A princípio, pode parecer estranho escrever um teste sem ao menos ter a respectiva função pronta. Mas a ideia por trás disso é justamente facilitar a criação do código e evitar a inserção de erros e bugs no sistema.

Afinal, o fato do teste já estar implementado faz com que a pessoa desenvolvedora tenha mais facilidade para entender o que supostamente o código deve fazer e possa implementar a funcionalidade já pensando em como o teste vai passar. Por consequência, o processo se torna mais rápido, já que criam-se códigos mais simples.

Fora isso, utilizando o TDD é possível garantir que cada pequena parte do sistema tenha um teste que atesta o seu funcionamento, o que melhora a qualidade final do software.

Como funciona o TDD e seu ciclo?

Como foi dito, o TDD se inicia com a criação de um teste para cada nova funcionalidade da aplicação. Mas isso não é tudo, o ciclo completo envolve cinco etapas diferentes que explicaremos logo abaixo. Veja!

5 etapas do TDD: novo teste, teste falhando, nova funcionalidade, teste passando, refatoração

Novo teste

Ao identificar uma nova funcionalidade para o sistema, a pessoa desenvolvedora deve iniciar a implementação de um teste específico para ela. Nessa etapa, é muito importante entender exatamente qual é a finalidade da função, seus requisitos, entradas e saídas, pois só assim você conseguirá criar o teste corretamente.

Teste falhando

Nesse momento, o teste já está pronto. No entanto, uma vez que o código da função ainda não foi implementado, o teste obviamente vai falhar ao ser executado. Esse resultado é totalmente esperado e a execução é feita apenas para demonstrar que algo novo foi acrescentado ao conjunto de testes do sistema.

Criar funcionalidade

Após a execução e falha do teste, chega o momento de escrever o código da nova funcionalidade. Nesse ponto, a única preocupação que deve ter em mente é fazer o teste passar. Ou seja, você pode criar o código da sua maneira, sem se prender às boas práticas e design patterns, o importante é que o teste passe sem que outros quebrem com a adição da nova funcionalidade.

Teste passando

Com a funcionalidade pronta, o teste é executado novamente. Dessa vez, no entanto, é esperado que ele passe. Porém, mesmo que o código esteja funcionando, é preciso lembrar que ele foi feito da forma mais simples possível e sem considerar as boas práticas de desenvolvimento. Isso nos leva ao próximo passo.

Refatorar

As boas práticas de desenvolvimento nos ensinam que um bom código deve ser simples, claro, coeso e menos acoplado possível. A refatoração é usada exatamente para esse objetivo. Nessa etapa, você deve melhorar o seu código, extraindo classes e interfaces, reduzindo o acoplamento, retirando as duplicidades e fazendo qualquer alteração que traga alguma otimização, desde que elas não insiram erros no código.

Quais as vantagens de usar o TDD?

Com a prática do TDD, a pessoa desenvolvedora de software desfruta de muitas vantagens. A criação de código limpo, claro e simples, por exemplo, é um dos benefícios mais evidentes desse método. Mas podemos citar outros, como:

  • cobertura de código: como existe um teste associado a cada funcionalidade, é possível ter a certeza de que todo o código foi executado e os erros são encontrados no início do desenvolvimento;
  • segurança: a implementação de novas funcionalidades é um processo delicado, pois há o risco de que a alteração gere bugs no sistema. Com o TDD, esse risco é reduzido, dando mais segurança para quem está desenvolvendo o software;
  • feedback rápido: visto que as funcionalidades são testadas logo após a sua criação, é possível obter um feedback quase instantâneo do seu funcionamento;
  • depuração simplificada: o processo de depuração se torna mais intuitivo, uma vez que, quando um teste falha, é mais fácil identificar onde se encontra o problema;
  • documentação do sistema: os próprios testes podem servir como um tipo de documentação do software. Afinal, ao lê-los, é possível entender facilmente como o código funciona;
  • melhoria no raciocínio: o TDD também é benéfico para as pessoas desenvolvedoras. Isso porque é necessário lapidar o processo de raciocínio a fim de elaborar códigos de qualidade que, ao mesmo tempo, atendam os requisitos, não insiram erros na aplicação, sejam simples e passem nos testes;
  • maior produtividade: como o código é flexível e limpo, gasta-se menos tempo com a correção de bugs e implementação de novas funcionalidades, consequentemente, a produtividade da equipe é maior.

O Desenvolvimento Orientado a Testes realmente é mais produtivo?

No Desenvolvimento Orientado a Testes, a entrega de uma funcionalidade pode ficar comprometida de início. No entanto, a sua manutenção ao longo prazo será muito bem recebida pela equipe, pois a partir dos testes conseguimos controlar exatamente o que está sendo adicionado ou modificado.

Muitas pessoas questionam a produtividade do desenvolvimento orientado a testes, isso porque sempre que se pensa em adicionar uma nova funcionalidade na aplicação, também se pensa muito na sua implementação e, consequentemente, nos seus testes.

Porém, esse estudo realizado em 2015 com 25 participantes do Brasil mostra que o TDD ajuda a pessoa desenvolvedora a pensar mais na funcionalidade que está sendo desenvolvida, bem como na sua constante refatoração de código. Isso faz com que o código seja mais limpo e que também exista o feedback visual de quais linhas já foram testadas ou não.

Por que é tão difícil aplicar o TDD?

O desenvolvimento orientado a testes não é uma tarefa fácil porque:

  • Você deve entender muito bem a estrutura do que está criando para se previnir de possíveis problemas.
  • O TDD não é uma prática usual para pessoas iniciantes, pois, para ser aplicado em um projeto, leva tempo e muita prática.
  • Às vezes não temos tempo hábil para implementar, ou seja, estamos em uma equipe de desenvolvimento e precisamos entregar a funcionalidade o quanto antes. Infelizmente, essa é uma prática muito comum no mundo do desenvolvimento de software e acaba diminuindo a qualidade do código a longo prazo.

Quando usar e quando NÃO usar o TDD?

Em alguns casos no desenvolvimento podemos optar por escrever ou não testes, aqui veremos mais sobre isso.

Quando usar TDD

Se o projeto no qual você está trabalhando tem uma expectativa de muitos recursos e uma longa vida útil, o TDD é a alternativa certa para gerenciar o controle de qualidade do seu código.

Dessa forma, os testes que foram criados antes vão servir para mostrar se o código tem bugs ou não caso haja a necessidade de voltarmos para uma funcionalidade antiga e adicionarmos mais algum código.

Quando não usar

Um dos casos que não faz sentido seguir o TDD é quando estamos desenvolvendo alguma demo de aplicação e queremos apenas mostrar que é possível realizar esse desenvolvimento.

Além do mais, não se faz necessário realizar testes em funcionalidades externas, ou seja, de bibliotecas ou frameworks. Mas caso o seu código seja dependente deste código externo, utilize objetos mocks, que são estruturas que simulam um comportamento de uma função para auxiliar neste desenvolvimento. 

Desenvolvedores podem criar testes para seus próprios códigos?

Ocorre uma certa confusão quando falamos de testes em nível em aplicação com testes do TDD. Mesmo que os dois sejam considerados testes, o teste em nível de aplicação é realizado majoritariamente por QAs (Quality Assurance) — uma pessoa profisisonal especializada em realizar testes em aplicações.

Já o teste do TDD deve ser escrito pela pessoa desenvolvedora que está criando a funcionalidade, pois não faz sentido realizar a troca na hora de escrever o teste, e também porque o teste deveria ser escrito antes da funcionalidade

No fim, cada empresa e equipe tem sua estratégia para isso. O recomendado é que a pessoa desenvolvedora sempre utilize as práticas de TDD para que tenha uma garantia mínima das funcionalidades que ele implementou.

O TDD torna o código menos seguro?

O TDD não torna o código menos seguro. Pelo contrário: a metodologia prática do TDD e a garantia de escrever testes e funcionalidades menores torna o código muito mais simples de ser entendido. A longo prazo, obtemos muitos benefícios com isso, dentre eles, mais segurança.

Simplificando, para fazermos os testes passarem logo, criamos códigos mais simples. Também o refatoramos para torná-lo mais claro e, por consequência, ele se torna mais seguro por causa dos testes. Aqui temos um ciclo de desenvolvimento fechado e perfeito para qualquer equipe.

Qual a relação entre TDD e Agile?

O TDD por si só é uma prática adotada pelas pessoas desenvolvedoras de uma equipe, ou seja, não abrange exatamente o que está no manifesto ágil. Sendo assim, podemos adotar o teste no desenvolvimento de software em qualquer camada, contanto que não prejudique o desempenho.

Desta forma, entre as possíveis metodologias ágeis criadas, a que mais se adequa com o TDD é a Extreme Programming. Nela, além seguirmos toda a estrutura do ágil, pensamos essencialmente na criação, refatoração e validação dos testes criados, gerando, assim, uma grande segurança nas entregas e modificações.

Quais as diferenças entre TDD, DDD e BDD?

Além do TDD, temos outras metodologias que têm siglas parecidas, no entanto são bem diferentes. Veja este comparativo:

Test Driven Development (TDD)Domain Driven Design (DDD)Behavior Driven Development (BDD)
O TDD é uma técnica de desenvolvimento que foca na criação de uma nova funcionalidade com base em testes, simplicidade e refatoração.O DDD é uma abordagem para modelar uma aplicação com base no domínio do negócio.O BDD também é uma técnica de desenvolvimento, só que focada na constante validação dos termos de uma aplicação
É realizado pelas pessoas desenvolvedoras.Também é realizado pelas desenvolvedoras e com a ajuda de uma especialista na área de negócio.É realizado pelo time em si.
É focado em teste unitário.É focado apenas no desenvolvimento do software.É focado na regra de negócio.
É uma metodologia de desenvolvimento.Também é uma metodologia de desenvolvimento.É uma metodologia de time.
A colaboração é feita pelas pessoas desenvolvedoras da aplicação.Além das pessoas desenvolvedoras, a especialista de negócio deve ser envolvido.A colaboração é feita pela equipe.

Quais as diferenças entre usar TDD e fazer os testes ao final?

A principal diferença entre TDD ou testar ao final está no tipo de feedback que obtemos ao realizar uma nova funcionalidade.

No TDD, os testes estão escritos e são sempre executados. Por isso, desde o momento em que é criado o novo recurso, obtemos feedbacks.

Já na abordagem de escrever o teste depois que o código foi escrito, temos um feedback mais demorado e muitas vezes até mais complexo, já que a lógica pode ter sido escrita de uma maneira complexa e a refatoração acaba sendo um retrabalho muito grande.

Por consequência da demora, criamos testes que avaliam a funcionalidade, mas que podem também comprometer a qualidade do código e o feedback obtido.

Como aplicar o TDD na prática? Exemplo simples e prático!

Quer aprender o básico do TDD? Vamos mostrar a seguir como utilizar essa abordagem em um código de Javascript.

1. Preparando ambiente

Para o nosso pequeno projeto utilizaremos: IDE, VS Code com Node e a biblioteca Jest (popularmente conhecida por integrar os testes na plataforma do Javascript).

Primeiro, criamos um projeto Node com o arquivo package.json.

{
  "name": "tdd-trybe",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {},
  "keywords": [],
  "author": "",
  "license": "ISC"
}

A partir disso, rodamos o seguinte comando para instalar o Jest.

npm install --save-dev jest

Ao final da instalação, é possível observar a criação do arquivo package-lock.json e a pasta node_modules. Depois, adicione o seguinte script no seu package.json:

"scripts": {
  "test": "jest"
},

Agora que temos o ambiente de teste criado, podemos seguir para a próxima etapa.

2. Escrevendo o nosso teste

Para o nosso exemplo enxuto, vamos escrever uma simples função que retorna a soma de dois valores.

Comece criando um arquivo chamado index.test.js na raíz do projeto. Nele, vamos adicionar o seguinte conteúdo:

test('espera que a soma de 1 + 2 seja 3', () => { // descrição do teste
  const a = 1 // primeiro valor
  const b = 2 // segundo valor
  const soma = 0 // soma dos dois valores

  expect(soma).toBe(3) // espera que a soma seja 3
});

Como podemos observar em nosso teste, esperamos que a soma dos dois valores seja 3. No entanto, a variável de soma tem o seu valor de 0. Isso porque ainda não implementamos a funcionalidade que realiza a soma.

Ao executarmos o nosso teste com o comando npm run test, será mostrado na tela que ele não passou e que o valor 0 não é igual a 3. Por isso, vamos à próxima etapa, que é escrever a nossa funcionalidade.

3. Escrevendo a nossa funcionalidade

A nossa funcionalidade é somar dois números, o que é relativamente simples. Vamos começar criando um arquivo chamado index.js e adicionando o seguinte conteúdo nele:

function somar(a, b) {
  return 0
}

module.exports = {
  somar, // exporta a funcionalidade
}

Declaramos uma função que retorna sempre 0 e exportamos essa funcionalidade para que possamos consumir no arquivo de teste. Depois, modificamos o nosso arquivo de teste com a seguinte lógica:

const { somar } = require('./index') // importamos a nossa funcionalidade

test('espera que a soma de 1 + 2 seja 3', () => { // descrição do teste
  const a = 1 // primeiro valor
  const b = 2 // segundo valor
  const soma = somar(a, b) // soma dos dois valores

  expect(soma).toBe(3) // espera que a soma seja 3
});

Pronto, combinamos o teste com a funcionalidade.

Lembrando que a nossa funcionalidade ainda não está concluída, devemos executar novamente os testes agora para obtermos o feedback negativo mais uma vez, mostrando que novamente o valor 0 não é igual a 3.

4. Finalizando o ciclo de desenvolvimento

Para terminarmos, precisamos corrigir a funcionalidade da função somar. O código correto ficará assim:

function somar(a, b) { // parâmetros da soma
  const soma = a + b // realiza a soma dos dois valores
  return soma // retorna o valor da soma
}

module.exports = {
  somar, // exporta a funcionalidade
}

Basicamente, somamos os dois valores e retornamos. Agora, ao rodarmos os testes, nos deparamos com um feedback positivo de todo esse esforço.

tela com o resultado dos testes após a finalização do ciclo de desenvolvimento TDD

O exemplo dado aqui foi simples e com o intuito de apresentar o mundo do TDD, desta maneira é possível se aprofundar nesta metodologia e utilizá-la em ciclos maiores.

O que não fazer durante o TDD? Os 6 principais erros!

Se você não quer falhar na hora de utilizar o TDD, siga essas dicas:

  • Sempre siga a ordem da metodologia;
  • Preocupe-se em refatorar e melhorar o código;
  • Não escreva vários testes simultaneamente;
  • Execute os testes e obtenha o seu feedback;
  • Não construa um ambiente de testes que demore muito tempo para ser executado;
  • Não combine testes de integração com os testes unitários. Cada um deve ter o seu próprio arquivo de teste.

Conclusão

Como foi possível perceber, o TDD é uma prática de desenvolvimento que trabalha bastante com a prevenção de erros e a qualidade de código. Sem dúvidas, é um método que traz grandes vantagens, mas, antes de aplicá-lo, é importante entender quais são as necessidades do projeto em que está trabalhando, a fim de verificar se esse é realmente o método mais adequado.

Gostou do conteúdo e quer saber mais sobre temas relacionados? Então, aproveite a visita ao nosso blog e entenda o que são os testes unitários!

0 Shares:
Deixe um comentário
Você também pode gostar