Vinicius Quaiato

{tecnologia, conceitos, negócios, idéias, práticas, .NET, ruby, osx, ios e algo mais}

TDD - Test-driven Development + c# - Parte II


TDD - Test-driven Development - Parte ITDD - Test-driven Development - Parte IIIApós o que foi apresentado no primeiro post da série, faremos nesta segunda parte um exemplo prático de TDD.Para efeito didático este será um exemplo bem simples e trivial, para que possamos focar nas práticas de TDD.Antes de começarmos gostaria de mencionar o "mantra do TDD":

# **"<span style="color: #ff0000;

">Red</span>, <span style="color: #008000;
">green</span>, <span style="color: #333399;
">refactoring</span>"**

Ou seja, escreva um teste que falhe, na verdade um teste que nem compila (<span style="color: #ff0000;

">vermelho</span>). Escreva um código que compile e faça o teste passar (<span style="color: #008000;
">verde</span>), mesmo que seja um código ruim. Então, após o teste passar melhoramos o código, com a finalidade de deixá-lo mais claro, coeso e simples (<span style="color: #333399;
">refactoring</span>).Tendo isso em mente, vamos para o nosso caso de uso em C#:<blockquote>Desenvolver uma aplicação bancária que controle saques, depósitos e transferências.</blockquote>Como eu disse o caso de uso é simples, para que foquemos no TDD.Vamos criar uma nova solution no Visual Studio. Aqui já começa a mudança de pensamento. Antes de criar o projeto da conta bancária, eu começo criando o projeto de testes da conta bancária. Eu gosto de pensar assim para ir me acostumando com a idéia do Test First.

TDD_criando_projeto_testesAgora que estamos com o projeto criado, vamos escrever nosso primeiro teste. Vocês vão perceber que a prática do TDD nos leva a pensar melhor em nossas classes. Vamos ver.Bom, em nosso primeiro teste vamos nos assegurar de que quando uma conta seja criada ela obrigatóriamente necessite de um depósito inicial:

[TestMethod]
public void Deve_Criar_Conta_Com_Deposito_Inicial(){    ContaBancaria conta = new ContaBancaria(50.0m);
    Assert.AreEqual(50, conta.SaldoAtual);
    }

Como podemos ver, este teste nem irá compilar, afinal, estamos criando o teste antes mesmo de criarmos a classe ContaBancaria.

public class ContaBancaria{

public decimal SaldoAtual { get;
    set;
    }

public ContaBancaria(decimal depositoInicial) { }
}

Assi podemos executar nosso teste. Eu gosto de utilizar dois atalhos CTRL + R + T (executa o teste corrente em modo debug) ou CTRL + R + A (executa todos os testes da solution em modo debug).Teremos o resultado como abaixo:TDD - executando primeiro testeEste teste falhou. Ótimo! Obtemos um <span style="color: #ff0000;

">red</span> e sabemos que estamos no caminho certo. Aconteceu que estávamos esperando um saldo de 50 e o saldo obtido foi 0.Agora devemos voltar ao código e fazer o teste passar:
public class ContaBancaria{

public decimal SaldoAtual { get;
    set;
    }

public ContaBancaria(decimal depositoInicial)    {        this.SaldoAtual += depositoInicial;
    }
}

Neste caso nossa mudança é bem pequena. Agora vamos executar o mesmo teste e ver o que acontece:TDD - executando primeiro teste verdePronto! Obtivemos um <span style="color: #008000;

">verde</span>, e isso quer dizer que podemos prosseguir, escrevendo os próximos testes. Antes disso acontecer, devemos lembrar do próximo passo: refactoring!Vamos voltar ao nosso código e entender o que pode ser refatorado.Me parece que a propriedade SaldoAtual não deveria ter um setter público, desta forma vamos torná-lo privado:
public class ContaBancaria{

public decimal SaldoAtual { get;

private set;
    }

public ContaBancaria(decimal depositoInicial)    {        this.SaldoAtual += depositoInicial;
    }
}

Agora devemos novamente executar nossos testes, para termos certeza de que não acabamos estragando nada.Agora precisamos garantir que o depósito inicial seja um depósito válido. Ou seja, o que acontece com um depósito inicial igual a 0? E se for menor que 0?De acordo com a regra de negócio que eu inventei, uma conta sempre deve ser criada com um depósito inicial. Quando quisermos carregar uma conta específica, utilizaremos outra notina e não o construtor público.Assim, vamos criar um deste que garanta que o depósito inicial seja válido.Vamos usar um atributo(attribute) do framework de testes do visual studio que nos permite testar se um determinado teste lança uma exceção - ExpectedException:

[TestMethod][ExpectedException(typeof(DepositoInicialInvalidoException))]
public void Deve_Lancar_Excecao_Deposito_Inicial_Invalido(){    ContaBancaria conta = new ContaBancaria(0);
    }

Para que este teste compile, vamos criar uma Exception:

public class DepositoInicialInvalidoException : Exception{

public DepositoInicialInvalidoException()        : base("Depósito inicial deve ser um valor maior que 0(Zero)!") { }
}

Agora vamos rodar nosso test. Pumba! Obtivemos um red. Afinal, não estamos validando o depósito inicial. Vamos fazer o código passar:

public ContaBancaria(decimal depositoInicial){
if(depositoInicial &lt;
    = 0)        throw new DepositoInicialInvalidoException();
    this.SaldoAtual += depositoInicial;
    }

Agora já podemos executar nossos testes (sim, devemos executar todos os testes, para ter certeza que nada quebrou no meio do caminho). Pronto, temos um verde. Vamos para o refactoring. A validação dentro do construtor não ficou muito elegante. Afinal, no futuro podemos ter outros tipos de validações, desta forma vamos refatorar:TDD - refatorandoAssim o visual studio criará para nós um método, e ficaremos com a seguinte estrutura:

public ContaBancaria(decimal depositoInicial){    Validar(depositoInicial);
    this.SaldoAtual += depositoInicial;
    }


private void Validar(decimal depositoInicial){
if(depositoInicial &lt;
    = 0)        throw new DepositoInicialInvalidoException();
    }

É importante que a cada refatoring, cada mudança de código, executemos novamente os testes. Mesmo que achemos que a mudança é pouca e pequena, isso nos fará ter o hábito de sempre executar os testes, e no futuro faremos isso para mudanças mais drásticas e severas.Bom pessoal, nesta segunda parte espero ter mostrado o início do TDD utilizando C# + Visual Studio.Na próxima parte deste artigo criaremos os testes para depósitos e saques.

Abraços, Vinicius Quaiato.

Voltar

Fork me on GitHub