Desenvolvimento orientado a teste/ Test Driven Development ou TDD

Você se lembra daquele dia não há muito tempo? Foi no final de uma longa e difícil semana terminando o novo release. Mas ao invés de comemorar, vocês estavam todos tentando freneticamente descobrir como consertar um bug. Vocês tinham o pessoal do suporte nos seus pescoços porque os clientes os perseguiam.

Naquela tarde, você decidiu: “Nunca mais”. Ou pelo menos não com a regularidade que esmaga a alma.

Desde então, você encontrou a resposta: Test Driven Development (TDD). E neste artigo você aprenderá o que é, o que você ganha e como fazer.

O que é Desenvolvimento orientado a teste/ Test Driven Development (TDD)?

Desenvolvimento orientado a teste é um processo no qual você escreve o teste antes de escrever o código. E quando todos os testes estão passando você limpa sua cozinha: você melhora o código.

No Entanto, Test Driven Development Não Se Trata de Testes

A premissa por trás do desenvolvimento orientado a testes, segundo Kent Beck, é que todos os códigos devem ser testados e refatorados continuamente. Isso certamente parece se tratar de testes, então, como assim?

Bem, os testes que você escreve em TDD não são o ponto, mas sim os meios.

A questão é que ao escrever testes primeiro e esforçar-se para mantê-los fáceis de escrever, você está fazendo três coisas importantes.

  1. Você está criando documentação, vivendo, respirando, especificações nunca desatualizadas (ou seja, documentação)..
  2. Você está (re)projetando seu código para fazê-lo e mantê-lo facilmente testável. E isso o torna limpo, descomplicado, fácil de entender e de modificar.
  3. Você está criando uma rede de segurança para fazer mudanças com confiança.

Portanto, Quais São os Benefícios do Test Driven Development?

Além dos benefícios mencionados na seção anterior, o TDD também o proporciona:

  • Notificação antecipada de bugs.
  • Diagnóstico fácil de bugs enquanto os testes identificam o que deu errado.

O que tudo isso significa para o seu negócio, é:

  • Além disso, melhora o fator de ônibus, pois o conhecimento não está apenas na cabeça e torna mais fácil a integração de novos contratados.
  • Reduz o custo das melhorias. Manter o código limpo também é como você minimiza o risco de complicações acidentais. E isso significa que você pode manter um ritmo constante na entrega de valor.
  • Com a rede de segurança, os desenvolvedores estão mais dispostos a fazer merge com suas mudanças e pull nas mudanças de outros desenvolvedores. E o farão com mais frequência. E então o trunk based development e continuous integration, entrega e implantação podem realmente decolar.
  • Reduz o número de bugs que “escapam” para a produção, logo, diminui os custos de suporte.

O Surpreendente Motivo para usar TDD

Software Developer Character. Vector Programmer Develops Code

Se todos esses benefícios não forem suficientes, há mais um motivo para usar TDD, um motivo que o surpreenderá.

Kent Beck afirma: “Muito simplesmente, test driven development visa eliminar o medo no desenvolvimento de aplicações”.
O medo é bom para mantê-lo vivo, mas é um assassino para o trabalho que precisa até mesmo do mínimo de cognição.

Hã, e Sobre “Desenvolvedores Não Devem Escrever os Testes para Testar seu Próprio Código?

TDD Developers

Sim, há boas razões para não deixar os desenvolvedores escreverem os testes para testar seu próprio código.

No entanto, este conselho se aplica aos testes de nível de aplicação.

Para testes de nível de desenvolvimento, conseguir que outra pessoa escreva os testes é como amarrar o cavalo atrás da carroça.
Os requisitos geralmente são vários níveis de abstração acima do código necessário para implementá-lo. Portanto, é preciso pensar no que se precisa fazer e como se fará. Escrever os testes primeiro é uma maneira excelente e eficiente de fazer isso.

E, lembre-se, TDD não se trata de testes.

E Onde o Test Driven Development Se Encaixa em Agile?

Em 1996, a equipe do projeto C3 da Chrysler praticou a programação test-first. “Nós sempre escrevemos testes unitários antes de lançar qualquer código, geralmente antes mesmo de escrever o código”, diz o estudo de caso do projeto intitulado “Chrysler Goes to “‘Extremes’”.”.

Os testes de escrita primeiro foram apenas uma das práticas utilizadas pela equipe C3. Em conjunto, essas práticas ficaram conhecidas como eXtreme Programming. Três membros dessa equipe, Kent Beck, Martin Fowler e Ron Jeffries, estavam entre as pessoas que escreveram e assinaram pela primeira vez o Manifesto Agile.

O test driven development é uma prática Agile essencial. Ela suporta diretamente o valor Agile de “Software funcional acima de documentação abrangente”. E o faz protegendo o software funcional com testes e criando a documentação como um subproduto natural.

Legal, Então Se Pratica o TDD

Test Driven Development (TDD)

Src: Spec-india.com

O test driven development é enganosamente simples. Fácil de explicar o que se faz, mas não tão fácil de fazer de fato. Mais sobre o porquê disso na próxima seção. Primeiro, vamos explicar o que você faz em TDD.

O Ciclo e as Fases do TDD

Test Driven Development significa passar por três fases. De novo e de novo e de novo.

  1. Fase vermelha: escrever um teste.
  2. Fase verde: fazer o teste passar, escrevendo o código que ele protege.
  3. Fase azul: refatorar.

Só isso? Sim, só isso mesmo.
Mas espere, há mais.

As Regras do TDD Como Explicadas pelo Tio Bob

Tio Bob (Robert C. Martin) definiu as regras do TDD no capítulo 5 “Test Driven Development” de seu livro The Clean Coder.

  1. Você não está autorizado a escrever qualquer código de produção a menos que seja para fazer um teste unitário falhado passar.
  2. Você não está autorizado a escrever mais de um teste unitário do que é suficiente para falhar; e falhas de compilação são falhas.
  3. Você não tem permissão para escrever mais código de produção do que o suficiente para passar no teste unitário falhado.

Por que seguir estas regras? Porque elas se destinam a facilitar sua vida.

Mas eu não estou satisfeito com a regra nº 2. Porque tratar os erros de compilação como falhas pode mascarar o fato de que um teste não tem afirmações. E isso é ruim, porque pode enganar você a pensar que um teste está passando quando o código está (em parte) não escrito ou simplesmente errado.

Dito isto, a intenção das regras é manter as coisas concentradas em cada fase e evitar que você fique em ciclos. Por experiência própria, isso ajuda muito a manter as coisas claras em sua cabeça. Por isso:

  • Durante a fase vermelha (escrever o teste), trabalhe somente no código de teste. Um teste falhado é bom. Pelo menos se for o teste em que você está trabalhando. Todos os outros devem ser verdes.
  • Durante a fase verde (fazer o teste passar), trabalhe apenas no código de produção que fará o teste passar e não refatore nada. Se o teste que você acabou de escrever falhar, isso significa que sua implementação precisa funcionar. Se outros testes falharem, você quebrou a funcionalidade existente e precisa retroceder alguns passos.
  • Durante a fase azul (refatoração), somente refatore de código de produção e não faça nenhuma alteração funcional.
    Qualquer falha no teste significa que você quebrou a funcionalidade existente. Ou você não completou a refatoração, ou precisa recuar.

Às vezes você encontrará oportunidades para refatorar o código de teste. Por exemplo, quando você tem um monte de testes [Fatos] separados em xUnit que só diferem nos argumentos que passam para o método em teste. Você pode substituí-los por um único teste [Teoria].

Meu conselho: não refatorar, mas acrescentar a teoria e quando isso estiver de acordo com os fatos, você pode remover os fatos.

Exemplos de Uso de TDD

Vamos tornar tudo isso um pouco mais concreto com um exemplo. Então, digamos que você seja encarregado de criar um método que converta os números decimais em números romanos.

Passo 1: Fase vermelha, escreva um teste.

Decimal 1 deve retornar “I”.

TDD Example

A execução do teste não é possível neste momento, porque a classe Romanizer ainda não existe e isso significa erros de compilação.

Passo 2: Fase verde, fazer o teste passar

Adicione a classe Romanizer e dê-lhe um método FromDecimal que pega uma integer e retorna uma string.

Eu gosto de ter certeza de que o teste ainda falha quando o código é compilado. Dessa forma, sei que estou começando com um teste falhado como resultado de afirmações nos testes.

Portanto, escrevo uma implementação que tenho certeza de que falhará.

TDD Example/p>

Execute os testes e sim, o teste falha. Boa!

TDD Example

Agora crie a implementação mais simples que fará o teste passar.

TDD Example

Bobo? Não. O código está correto e faz o teste passar.

TDD Example

A criação de um algoritmo que possa funcionar é prematura nesta fase. Você pode acertá-lo, mas é mais provável que não o faça. E isso pode te colocar em problemas (veja mais abaixo).

Passo 3: Fase azul, refatorar

Ainda não há muito para refatorar, portanto, para o próximo teste.

Passo 4: Fase vermelha, escreva um teste

O decimal 2 deve retornar “II”.

TDD Example

Faça todos os testes para ver este falhar. Isto é muito importante! Ele permite que você tenha certeza de que é sua implementação que o fará passar e não a falta de afirmações em seu teste.

TDD Example

Ok. Para a fase verde.

Passo 5: Fase verde, faça o teste passar

Mais uma vez, escreva o código mais simples que fará o teste passar.

TDD Example

Hmm. Não gosto que o if-else-if fique muito grande, mas vamos primeiro executar os testes.

TDD Example

And yes, it does make all the tests pass.

Passo 6: Fase azul, refatorar

Esta estrutura if-else-if não é muito elegante, mas dois casos ainda não merecem ser refatorados, e assim por diante para o próximo teste.

Passo 7: Fase vermelha, escreva um teste

O decimal 3 deve retornar “III”.

TDD Example

E executar todos os testes para ver este falhar. (E nenhum outro!)

TDD Example

Passo 8: Fase verde, fazer o teste passar

Mais uma vez, o código mais simples para fazer o teste passar.

TDD Example

Isto está começando a ficar bem feio, mas primeiro execute os testes.

TDD Example

Sim, tudo verde, então podemos finalmente fazer algo a respeito dessa estrutura se-else-if, porque 3 casos merecem uma refatoração, como agora se aplica a Regra de 3.

Passo 9: Fase azul, refatorar

O padrão é claro. Você precisa de tantos “I” quanto o número que foi passado.

TDD Example

Execute todos os testes para garantir que cada um deles ainda passe.

TDD Example

Algumas reflexões extras

Claro que, sabendo como funcionam os numerais romanos, o padrão não se manterá.
Mas quebrar o cérebro com um algoritmo de antecedência não é o caminho a seguir. Você provavelmente acabará ajustando-o para cada teste que você adicionar. E ficar mal-humorado quando cada ajuste provoca o fracasso de diferentes testes.

Quando você escreve o código e o refatora para algo mais simples, você aumenta o algoritmo à medida que você avança. Uma maneira muito melhor e mais fácil de fazer isso.

Regras de Refatoração

Quando você refatora, não o faz de forma aleatória. Você segue um processo estruturado para limpar o código.

Você identifica code smells e aplica uma refatoração específica para removê-los. Martin Fowler escreveu o livro sobre como fazer isso: Refactoring: Improving the Design of Existing Code.

O objetivo da refatoração é melhorar a extensibilidade de seu código através de

  • melhorando a legibilidade
  • facilitando a realização de modificações
  • reduzindo a complexidade
  • melhorando a arquitetura interna (modelo de objeto) e tornando isso mais expressivo

O que é realmente importante é que a refatoração é o que deixa o código limpo, descomplicado, fácil de entender, de modificar e de testar. E você já leu o que isso lhe proporciona.

Por Que é Tão Difícil Exercer o TDD?

software development tdd

Praticar o TDD não é um mar de rosas. Pelo menos não a princípio. Aqui estão os motivos.

  • Porque você tem que pensar no que quer que seu código realize, e como protegê-lo contra falhas (teste-o).
  • Porque ele possui uma curva de aprendizagem íngreme. Você precisa aprender os princípios e design patterns para criar um código limpo e como refatorá-lo para mantê-lo dessa forma.
  • Porque o código luta de volta. O código existente que não está sendo testado o prende entre. Você precisa refatorá-lo para colocá-lo sob teste e você precisa de testes para refatorá-lo. Recomendo muito o livro Working effectively with Legacy Code de Michael C. Feathers para isso.
  • Porque você experimenta os custos do TDD imediatamente e o custo de não praticá-lo muito mais tarde. A atração de deixá-lo de lado é forte. Você sabe que pagará o preço quando os relatórios de erros começarem a inundar. Mas isso é no futuro, não é?

Como Você Pode Falhar no TDD — Quais São os Erros Comuns?

Você pode falhar na prática do TDD de muitas maneiras diferentes:

  • Não seguir a abordagem de test-first.
  • Não refatorar o tempo todo.
  • Escrever mais de um teste de cada vez.
  • Não realizar testes com frequência, perdendo o feedback antecipado deles.
  • Escrever testes que são lentos. O conjunto completo deve ser concluído em minutos ou até segundos.
  • Usando seus testes unitários para fazer testes de integração. Não há nada de errado em usar sua estrutura de testes unitários para executar testes de integração. Mas os testes de integração são, por natureza, lentos, então você precisa colocá-los em sua própria suíte de testes.
  • Escrever testes sem fazer afirmações.

Escrever testes para código trivial, tais como accessors e vistas sem lógica.

Recursos Para Aprender e Melhorar

Qual é a Diferença entre TDD e BDD?

TDD-BDD-Difference

Behavior Driven Development e Test Driven Development são ao mesmo tempo similares e diferentes.

  • Ambos empregam abordagens de test-first, mas não se tratam de testes.
  • O BDD trata de melhorar a colaboração e a comunicação entre desenvolvedores, testadores e profissionais de negócios. Para garantir que o software atenda tanto os objetivos comerciais quanto às exigências do cliente.
  • TDD é sobre design e especificações em nível de código.
  • O BDD trabalha no nível da aplicação e dos requisitos. TDD foca no nível do código que implementa esses requisitos.
  • TDD é, ou pode ser usado como a fase “Faça os testes passarem” do BDD.
  • No TDD você pode, mas não precisa, usar técnicas de BDD até o menor nível de abstração.
  • O BDD não tem uma fase de refatoração como o TDD.

Não Espere, Vá Atrás de Sua Cama de Rosas

Como você já viu, o Test Driven Development é uma técnica simples de descrever, mas muito mais difícil de praticar. Como com qualquer habilidade, você precisará praticar muito para internalizá-la.

Para torná-la sua segunda natureza e chegar ao ponto em que você está desenvolvendo mais rapidamente com TDD do que sem ele. Mas, como você também já ouviu, as recompensas são belas, belas de verdade.

Desenvolvendo com confiança. Nunca temendo outro release. Entregando valor a um ritmo sustentável previsível. Uma bela cama de rosas! Então, dê o mergulho. Quanto mais cedo você começar, mais cedo você terá a prática, e mais cedo colherá os benefícios.

Desenvolvimento Orientado a Testes (TDD)

A vida é boa quando suas equipes Agile estão sincronizadas!

Contate-Nos hoje para uma demonstração personalizada do SwiftEnterprise! Ou inscreva-se para atualizações abaixo.

Solicitar Demonstração