Compartilhar via


TDD - Test Driven Development em .NET Part 1: Princípios Básicos RED, Refactor & Green


  • O que é o TDD? E Por que usar?

Olá a todos! Quanto tempo não é mesmo!! Desculpem a todos que são seguidores do meu site pela ausência de conteúdo aqui. Houve muitas mudanças desde o meu último post até hoje. Realizei uma mudança e fui morar fora do país por 1 ano para fins de trabalho e mais serviço voluntário. Foi uma experiência muito edificante e que recomendo a todos fazerem em alguma parte de suas vidas!!=]

Bom... vamos falar de um assunto, que há muito tempo já estava querendo escrever: TDD! =] . Mas... o que seria o TDD?

Vamos a definição do TDD encontrado na Wikipédia:

"Test Driven Development (TDD) ou em português Desenvolvimento guiado por testes é uma técnica de desenvolvimento de software que baseia em um ciclo curto de repetições: Primeiramente o desenvolvedor escreve um caso de teste automatizado que define uma melhoria desejada ou uma nova funcionalidade. Então, é produzido código que possa ser validado pelo teste para posteriormente o código ser refatorado para um código sob padrões aceitáveis. Kent Beck, considerado o criador ou o 'descobridor' da técnica, declarou em 2003 que TDD encoraja designs de código simples e inspira confiança[1] . Desenvolvimento dirigido por testes é relacionado a conceitos de programação de Extreme Programming, iniciado em 1999,[2] mas recentemente tem-se criado maior interesse pela mesma em função de seus próprios ideais.[3] Através de TDD, programadores podem aplicar o conceito de melhorar e depurar código legado desenvolvido a partir de técnicas antigas."

Infelizmente, muitos desenvolvedores não fazem o uso do TDD quando desenvolvem os seus códigos, fazendo com que perca a garantia e principalmente a qualidade do código desenvolvido. Não testar o código desenvolvido = não documentar aquilo que você desenvolveu. Na grande maioria os que não não praticam os testes unidade ou porque: não tem segurança naquilo que desenvolveu, aprendizado, falta de cultura, documentação e trabalho em equipe, a falta também de um suporte gerencial, ou seja, toda a empresa tem que "abraçar" a ideia e ver que perder tempo escrevendo testes é sinônimo de qualidade do produto que está sendo desenvolvido. E um outro fator muito importante: muitos desenvolvedores acharem que, aquilo que desenvolveram não tem a necessidade de testar, uma vez que tem uma larga experiencia como desenvolvedores.

Existe um outro problema por trás do uso do TDD...

https://code4coders.files.wordpress.com/2016/03/tdd_2.jpg

Sim.... há muitos programadores que desenvolvem seus códigos e somente quando terminam de codificar que começam a escrever os seus testes... #ERRADO #FAIL!!!

E já escutei várias vezes de muitos desenvolvedores que falam algo do tipo....

https://code4coders.files.wordpress.com/2016/03/tdd_3.jpg

Mas... uma vez que você aprende e vê que....

https://code4coders.files.wordpress.com/2016/03/tdd_4.jpg

... sua vida como programador e desenvolvedor será muito diferente! Mas, por quê?

Primeiro que, uma vez que você desenvolve seus códigos realizando o TDD, pode ter certeza que seu código estará muito bem documentado, com muito mais qualidade e principalmente muito elegante! =]

Segundo, você ganha confiança ao codificar e a produtividade do seu trabalho também aumentará. E existe algo melhor que fazer um deploy de um determinado projeto sem que necessite posteriormente depurar o seu projeto devido um código mal desenvolvido?! Claro que não!!

Resumindo: realizar testes de unidade (TDD) evitará um grande de defeitos no código e retrabalho! Então, como a figura acima: "Unit Test. Work!" =]

Mas, vamos ao que interessa.... como faço para realizar um Teste de Unidade (TDD)?

  • Red, Green, Refactor! E só! =]

O ciclo de desenvolvimento para realizar os Testes de Unidade se resume em:

  1. RED: Escreva um teste de unidade falho.
  2. GREEN: Torne o teste bem-sucedido.
  3. REFACTOR: Refatore.

   https://code4coders.files.wordpress.com/2016/03/tdd.png?w=680   

Não vou entrar no conceito teórico... até para fazer vocês realizarem pesquisas a respeito... vamos colocar a mão na massa e desenvolver um Teste de Unidade. Nesse caso, estarei usando a linguagem C# juntamente com o nUnit.

Só para salientar que, os Testes de Unidade podem ser feitos e implementados em qualquer linguagem de programação que tenha suporte. ;)

 

  • Colocando a mão na massa: Criando o primeiro Projeto com TDD! =]

Como falado anteriormente, estarei realizando uma série de artigos sobre Test Development em C# com nUnit. E para começar.. peço que vocês...

**Passo 1: **Abre o Visual Studio 2013 e crie uma 'Blank Solution' e escreva o nome do projeto como: 'TddPrimeiroProjeto', assim como segue a imagem abaixo:

https://code4coders.files.wordpress.com/2016/03/figura-01-2.jpg

**Passo 2: **Agora já com a sua Solution já criada, clique com o botão direito encima da Solution e clique em: Add -> New Project. Adicione uma nova Class Library em C# chamada: 'Application.Domain'. Aproveita para remover o arquivo 'Class1.cs' uma vez que não faremos uso dela!

O projeto deve estar com a seguinte estrutura:

  https://code4coders.files.wordpress.com/2016/03/figura-02_tdd.jpg

Criamos o projeto 'Domain' com o objetivo de representar a parte lógica do negócio que iremos testar! ;)

**Passo 3: **Vamos agora criar uma outra 'Class Library' em C# para a aplicação e vamos chamar de: 'Application.Domain.Tests'. E novamente delete o arquivo gerado 'Class1.cs'. Como iremos testar a lógica do domínio já criada, vamos adicionar a referencia do projeto 'Application.Domain' para o 'Application.Domain.Tests'.

https://code4coders.files.wordpress.com/2016/03/figura-03_tdd.jpg

**p.s.: sempre quando for adicionar uma determinada referencia ao projeto, sempre clique em 'Build - > Build Solution', okay? **

**Passo 4: **Agora vamos precisar incluir no nosso projeto o framework de testes na nossa Solution. Para isso, iremos utilizar o framework nUnit. Existe o xUnit... mas... com o tempo poderei escrever uma matéria sobre o xUnit... nessa série iremos utilizar o nUnit por ser o mais usado e mais conhecido, uma vez que xUnit é um framework muito recente da Microsoft.
Para adicionar o nUnit iremos usar o 'Manage NuGet Packages' e para acessá-lo, clique com o botão direito em 'References' do projeto 'Application.Domain.Tests'. Abrirá uma nova janela. Nessa mesma janela, escreva 'nUnit' e então instale os dois pacotes: nUnit e nUnit.Runners, como segue a imagem abaixo:

  • nUnit

https://code4coders.files.wordpress.com/2016/03/screen-shot-03-14-16-at-08-16-pm.jpg   

  • nUnit.Runners.Net4

https://code4coders.files.wordpress.com/2016/03/screen-shot-03-14-16-at-08-19-pm.jpg

Talvez vocês estejam se perguntando: Por que baixar o nUnit.Runners? Simples. Porque é ele que será o nosso 'Runner Test'. Ou seja, será ele que irá executar os testes em nosso projeto! ;)

Bom... a estrutura do projeto deverá estar da seguinte maneira:

https://code4coders.files.wordpress.com/2016/03/screen-shot-03-14-16-at-08-24-pm1.jpg
É muito importante que na Solution contenha esses 3 arquivos! :)

Agora que já está tudo pronto, vamos criar o nosso primeiro teste em nosso projeto! YEAH!!! :)

Clique com o botão direito na 'Application.Domain' e vamos adiocionar uma nova classe. Clique com o botão encima 'Application.Domain -> Add -> Class' e nomeie como: 'Calculadora.cs'.

https://code4coders.files.wordpress.com/2016/03/screen-shot-03-14-16-at-08-46-pm.jpg

Iremos desenvolver e implementar um teste bem fácil, como podem perceber... Mas... durante a série... vamos criar outros projetos conforme a dificuldade de cada post que irei tratar aqui ;)

Bom... com a classe criada, escreva o código abaixo:

namespace Application.Domain
{
    public class  Calculadora
    {
        public int  Somar(int  numero1, int  numero2)
        {
            return numero1 + numero2;
        }
 
        public int  Multiplicar(int  numero1, int  numero2)
        {
            return numero1 * numero2;
        }
    }
}

Como podem observar, criamos 2 métodos bem simples para a nossa classe 'Calculadora'. Um método que irá somar 2 números e terá que retornar a soma do mesmo e o mesmo com o método 'Multiplicar'. Agora vamos criar a nossa classe de teste no projeto 'Application.Domain.Tests'. Mas antes, preciso esclarecer algumas coisas com respeito ao framework nUnit.

Um teste nada mais é do que uma classe normal em C# onde contem alguns atributos específicos. Em esses atributos declaramos a classe que será usada para realizar os testes ou um determinado método que obterá um método de testes para que possamos executar a lógica do código desenvolvido. Cada estrutura de testes obterá esses atributos e eles pode ser muito diferentes de cada um, mas servindo com o mesmo propósito.

Em nUnit uma classe que será testada, declaramos acima dela o atributo 'TestFixture' e um método de teste com o atributo de Test. Estes atributos ajudam a identificar a execução de onde está partindo os testes. Não é somente clicar em executar os testes, mas nós devemos dizer ao código onde e qual método será testado ;)

Crie agora no projeto 'Application.Domain.Tests' uma classe chamada: 'CalculadoraTeste.cs'. E logo em seguida desenvolva o seguinte código:

01.using NUnit.Framework;
02. 
03.namespace Application.Domain.Tests
04.{
05.    [TestFixture]
06.    public class  CalculadoraTestes
07.    {
08.        [Test]
09.        public void  DevoSomarDoisNumeros()
10.        {
11.            var sut = new  Calculadora();
12. 
13.            var result = sut.Somar(1, 2);
14. 
15.            Assert.That(result, Is.EqualTo(3));
16.        }
17. 
18.        [Test]
19.        public void  DevoMultiplicarDoisNumero()
20.        {
21.            var sut = new  Calculadora();
22. 
23.            var result = sut.Multiplicar(2,10);
24. 
25.            Assert.That(result, Is.EqualTo(20));
26.        }
27.    }
28.}

Calma! Vou explicar agora o que está acontecendo aqui! :)

Lembra que acima falei que,  em determinado método que estamos realizando o teste usamos algumas palavras-chaves para indicar o que e como devemos testá-lo? Note que no código a primeira coisa que devemos usar acima do método a ser testado é a palavra-chave 'TestFixture'. Mas, para usarmos essas palavras-chaves precisamos usar a biblioteca: 'NUnit.Framework'.

Ok! Notem que criamos dois métodos para testar a lógica que criamos no 'Calculadora.cs'. Agora observem um detalhe muito importante para quem está entrando e começando a criar seus primeiros testes: Os nomes dos métodos! Sim. Os nomes dos métodos devem dizer justamente aquilo que está sendo testado. Para que não haja uma interpretação ambígua sobre o que está sendo testado e principalmente para que num futuro se o teste que você criou cair nas mãos de outro desenvolvedor, ele saberá justamente o que está sendo feito ali. Isso é muito importante!!! Sinceramente me irrita profundamente quando pessoas criar métodos ou até mesmo variáveis indecifráveis como, por exemplo:

**var n - > em vez de escrever var numero **

ou para piorar....

public void Cri_Emp() {...} -> em vez de escrever public void CriarEmpresa() {...}

Bom.. isso é um assunto para panos a manga... e quem sabe fica para um próximo post! ;)

Então vejam que os nomes dos métodos dizem justamente o que os testes devem fazer!!! Mas, você outra vez deve estar se perguntando: "Glaucia! Mas, você disse que os nomes das variáveis devem seguir uma nomenclatura onde deve ser decifrável e entendível para qualquer desenvolvedor?!! E por que colocaste: sut e result?!!!!" Na primeira vez que eu vi um dos melhores programadores/desenvolvedores (Francisco Rosales), com a qual eu tive a honra e a grande oportunidade de trabalhar com ele na Argentina na empresa GlobalLogic LATAM, realizando um teste de unidade no código, fiz essa mesma pergunta:

"Che! Por que você colocou os nomes das variáveis nos métodos como: sut e result?!"

A resposta dele foi bem sucinta e muito técnico, como sempre @.@:

"Glaucia... por padrão devemos chamar as variáveis de sut e result. No sut é onde definimos o que estamos testando. E result, como pode perceber é o resultado esperado do que estamos testando. Então, por padrão de nomenclatura é assim."  Genial! Não é mesmo!! @.@

SUT é acrônimo em inglês que significa System Under Test (sistema em teste) ou seja, fazendo referencia daquilo que estamos testando.

Assim que, desde então... quando crio os meus testes sempre declaro as minhas variáveis de teste com sut e result. :)

Bom... retornando.... Os dois métodos estão fazendo justamente o que precisamos: que retorne a soma ou a multiplicação de dois número. Mas, o que realmente vai verificar se o teste criado está correto? É aí que usamos a palavra-chave 'Assert'. Os Asserts diz ao 'test runner' se o teste irá falhar ou se será bem-sucedido! Observem na imagem abaixo o que ele faz:

https://code4coders.files.wordpress.com/2016/03/screen-shot-03-14-16-at-10-12-pm.jpg

A imagem por si só já explica! ;)

Em um próximo artigo vou explicar detalhadamente sobre os Asserts... pois há muito coisa envolvida e que podemos utilizar dessa palavra-chave para realizar excelente e elegantes testes de unidade! :)

Bom... agora vamos executar o nosso teste. Mas, antes de fazermos isso, precisamos baixar um outro pacote: 'NUnit Test Adapter'. Para isso, vai até o menu do Visual Studio e clique em: 'Tools -> Extensions and Updates', abrirá uma janela. Nessa mesma janela escreva no Search: 'nUnit' e em seguida: 'nUnit Teste Adpater' (não se esquecer de escolher a opção: Online!!)

Antes de fazer o 'Download' clique encima da Solution senão não irá executar o teste! ;)

Depois clique em 'Download' e irá baixar o pacote. Assim que terminar de realizar o download, será necessário fazer um restart do Visual Studio para que as mudanças tenham efeito.

Então, após reabrir o Visual Studio e o projeto, execute o teste em: Test -> Run -> All Tests (ou simplesmente o atalho: CTRL+R, A) que irá compilar e executar os testes através do nUnit. Ao final, no lado esquerdo do Visual Studio aparecerá a seguinte janela informando se o seu teste passou ou não:

https://code4coders.files.wordpress.com/2016/03/screen-shot-03-14-16-at-10-44-pm.jpg

Que felicidade, não é mesmo!Deu #GREEN!!! :) Bom.... os testes passaram. Mas, lembra-se que o conceito inicial do TDD não é só criar testes que sejam bem-sucedidos? Vamos criar agora um teste que venha a falhar. Para isso vamos criar um outro método de teste na nossa aplicação! ;)

Acrescente o código abaixo:

01.[Test]
02.public void  DevoDiminuirDoisNumeros()
03.{
04.     var sut = new  Calculadora();
05. 
06.     var result = sut.Diminuir(10, 6);
07. 
08.     Assert.That(result, Is.EqualTo(2));
09.}

Já notaram no código o que vai acontecer aqui né.... o resultado esperado deveria ser 4 e não 2. Então, com certeza esse teste irá falhar. Execute o teste e veja o que aacontecerá... :P

https://code4coders.files.wordpress.com/2016/03/screen-shot-03-14-16-at-11-04-pm.jpg
....e deu #RED! Ou seja, o nosso teste falhou. Mas, vamos explorar um pouco mais os recursos do Test Explorer para podermos entender por que o nosso teste falhou. Dê um duplo clique no método que falhou. Ao clicar note a observação no Summary... ele já explica o que aconteceu e porque o seu código falhou: https://code4coders.files.wordpress.com/2016/03/screen-shot-03-14-16-at-11-07-pm.jpg

Notem que a ferramenta em si, já facilita a vida do programador/desenvolvedor! Ô benção!!! :) Veja que o teste em si falhou porque o resultado esperado era 4 não 2! É de suma importância todos aqueles que procurarem desenvolver os seus testes utilizando o VS e as ferramentas adicionais da IDE para tentar descobrir e interpretar porque os testes desenvolvidos falharam.

Aqui nesse caso, forçamos o erro... Mas, pode acontecer do desenvolvedor codificar um determinado método de teste, pensando que está tudo certinho e quando executa o código... Puft! Deu #RED. Com isso, antes que entre em qualquer desespero... procure analisar o que fez de errado no momento que desenvolveu o seu teste, caso o mesmo venha a falhar. ;)

Bom... vamos acertar isso né. Agora mude o método de teste: 'DevoDiminuirDoisNumeros()' para o código a seguir:

01.[Test]
02.public void  DevoDiminuirDoisNumeros()
03.{
04.     var sut = new  Calculadora();
05. 
06.     var result = sut.Diminuir(10, 6);
07. 
08.     Assert.That(result, Is.EqualTo(4));         
09.}

Agora execute os teste e ....... Voilà! Agora sim! Deu #GREEN! :)

:) https://code4coders.files.wordpress.com/2016/03/screen-shot-03-14-16-at-11-16-pm.jpg
 

Observem que, realizamos um refactoring do nosso código... que seria o terceiro passo para concluir o ciclo de desenvolvimento do TDD, para que enfim ele venha a se tornar #GREEN! Entrarei em mais detalhes sobre o tema do Refactoring... uma vez que você desenvolve um determinado projeto, onde contém inúmeras regras de negócio e nelas contidas muitas lógicas, se faz muito necessário criar testes de unidades em esses métodos... e muitas das vezes, se faz necessário refatorar o código, para que o mesmo seja executado de maneira mais rápido, mais clean e principalmente começar a escrever códigos mais elegantes! Não basta apenas que o seus testes passem! Lembre-se que os testes são a documentação do seu código!!! :) 

Por hoje é só! UFA! :D

*Spoiler:* Esse tutorial terá continuação!!! =D

Para o próximo artigo explicarei com mais detalhes os Asserts e como criar testes mais detalhados, onde iremos testar o Método por exemplo! E como tornar um determinado código mais clean e elegante ao refatorar o código! :D

Fiquem à vontade em dar um 'fork' no projeto desenvolvido através da minha conta do GitHub! Tem diversos repositórios com outros projetos meus desenvolvidos. Vale a pena dar uma olhada ;)

 Qualquer sugestão, dúvida ou novos temas, não deixem de comentar abaixo.

 Até a próxima e Fui!

p.s.: Código do projeto aqui