Testes de Software - Criando testes unitários p/código gerenciado no VS 2015


Este tutorial tem como objetivo guiá-lo através da criação, execução, e personalização de uma série de testes unitários usando o Unit Test Framework da Microsoft para código gerenciado e o Visual Studio Test Explorer.

Vamos iniciar com um projeto C# que está em desenvolvimento, criar testes que verificam o código, executar os testes, analisar os resultados e depois, vamos alterar o código do projeto e reexecutar os testes.

Nota: Este artigo esta totalmente baseado no original : https://msdn.microsoft.com/en-us/library/ms182532.aspx#BKMK_Prepare_the_walkthrough  sendo uma tradução livre powered by Macoratti com algumas alterações e adaptações.

Recursos usados

Preparando o ambiente no VS 2015 Community

Abra o VS Community 2015  e clique em New Project;

A seguir selecione Visual C# -> Class Library,  informe o nome Banco e clique no botão OK;

Será criado um projeto na janela Solution Explorer contendo a classe Class1.cs.

Altere o nome da classe para ContaBancaria.cs  e inclua o código abaixo nesta classe :

using System;
namespace Banco
{
    public class ContaBancaria
    {
        private string nomeCliente;
        private double saldo;
        private bool bloqueada = false;
        private ContaBancaria()
        {
        }
        public ContaBancaria(string nomeDoCliente, double saldoDaConta)
        {
            nomeCliente = nomeDoCliente;
            saldo = saldoDaConta;
        }
        public string NomeCliente
        {
            get { return nomeCliente; }
        }
        public double Saldo
        {
            get { return saldo; }
        }
        public void Debito(double valor)
        {
            if (bloqueada)
            {
                throw new Exception("Conta Bloqueada");
            }
            if (valor > saldo)
            {
                throw new ArgumentOutOfRangeException("valor maior que o saldo");
            }
            if (valor < 0)
            {
                throw new ArgumentOutOfRangeException("valor menor que zero");
            }
            saldo += valor; // código com erro 
        }
        public void Credito(double valor)
        {
            if (bloqueada)
            {
                throw new Exception("Conta bloqueada");
            }
            if (valor < 0)
            {
                throw new ArgumentOutOfRangeException("valor menor que zero");
            }
            saldo += valor;
        }
        private void ContaBloqueada()
        {
            bloqueada = true;
        }
        private void ContaNaoBloqueada()
        {
            bloqueada = false;
        }
        public static void Main()
        {
            ContaBancaria ba = new ContaBancaria("Mr. Macoratti", 11.99);
            ba.Credito(5.77);
            ba.Debito(11.22);
            Console.WriteLine("O saldo atual é R${0}", ba.Saldo);
        }
    }
}
Classe ContaBancaria :

Campo :

  • bloqueada

Construtores:

  • ContaBancaria()
  • ContaBancaria(string nomeDoCliente, double saldoDaConta)

Propriedades :

  • NomeCliente
  • Saldo

Métodos :

  • Debito(double valor)
  • Credito(double valor)
  • ContaBloqueada()
  • ContaNaoBloqueada()


Nota: 

O método Debito() possui um erro de código  que foi provocado intencionalmente para o propósito do artigo.

Salve a classe ContaBancaria e no menu Build clique em Build Solution.

Ao final teremos uma solução Banco com um projeto chamado Banco e uma classe chamada ContaBancaria que contém os métodos que iremos testar.

Vamos focar no método Debito(double valor) da classe ContaBancaria.

Esta classe é chamada quando o dinheiro for sacado da conta e contém o seguinte código :

       public void Debito(double valor)
        {
            if (bloqueada)
            {
                throw new Exception("Conta Bloqueada");
            }
            if (valor > saldo)
            {
                throw new ArgumentOutOfRangeException("valor maior que o saldo");
            }
            if (valor < 0)
            {
                throw new ArgumentOutOfRangeException("valor menor que zero");
            }
            saldo += valor; // código com erro 
        }

Criando um projeto de Teste Unitário

Vamos incluir na solução Banco um projeto de teste unitário para realizar os testes em nossa classe ContaBancaria.

No menu File clique Add -> New Project;

Selecione Visual C# -> Test e o template Unit Test Project e informe o nome BancoTeste e clique no botão OK;

Será criado o projeto BancoTeste na solução.

Vamos incluir uma referência ao projeto Banco no projeto BancoTeste.

Clique com o botão direito do mouse sobre o projeto BancoTeste  e clique a seguir em Add -> Reference;

Na janela Reference Manager clique em Projects e marque o projeto Banco conforme mostrado abaixo:

Criando a classe de teste

Note que no projeto BancoTeste foi criada uma classe de teste chamada UnitTest1.cs que podemos ver na figura abaixo:

Observe o namespace  Microsoft.VisualStudio.TestTools.UnitTesting usado nesta classe. É ele que fornece as classes que dão suporte aos testes unitários e contém muitos atributos que identificam informações de testes.

Precisamos de uma classe de teste para verificar a classe ContaBancaria e vamos aproveitar essa classe criada alterando o seu nome para ContaBancariaTestes.

Para isso clique com o botão direito sobre a classe UnitTest1.cs e a seguir clique em Rename informando o nome ContaBancariaTestes.

Vamos incluir também nesta classe de testes o namespace using Banco; para podermos acessar a classe ContaBancaria. Ao final teremos o código abaixo:

using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Banco;

namespace BancoTeste
{
    [TestClass]
    public class ContaBancariaTestes
    {
        [TestMethod]
        public void TestMethod1()
        {
        }
    }
}

Os requisitos mínimos para uma classe de teste são os seguintes :

Podemos ter outras classe no projeto de teste unitário que não possuam o atributo [TestClass] e podemos ter outros métodos nas classes de testes que não tenham o atributo [TestMethod] para usarmos em nossos métodos de testes.

Criando o primeiro método de teste

Vamos começar criando métodos de testes unitários para verificar o comportamento do método Debito(double valor) da classe ContaBancaria.

Fazendo uma análise no método Debito(), vamos determinar pelo menos 3 comportamentos que precisamos verificar :

  1. O método lança uma exceção ArgumentOutOfRangeException  se o valor do débito for maior que o saldo;
  2. O método lança uma exceção ArgumentOutOfRangeException se o valor do débito for menor que zero;
  3. Se as verificações feitas em 1 e em 2 forem satisfeitas o método subtrai o valor do saldo da conta;

No primeiro teste vamos verificar que um valor válido realize o saque do valor correto da conta.

Para isso inclua o método Debito_ComValorValido_AtualizaSaldo na classe ContaBancaria com o código abaixo:

        [TestMethod]
        public void Debito_ComValorValido_AtualizaSaldo()
        {
            // arranjo
            double saldoInicial = 11.99;
            double valorDebito = 4.55;
            double saldoEsperado = 7.44;

            ContaBancaria conta = new ContaBancaria("Mr. Macoratti", saldoInicial);
            // debita
            conta.Debito(valorDebito);
            // assert
            double saldoAtual = conta.Saldo;
            Assert.AreEqual(saldoEsperado, saldoAtual, 0.001, "Conta não foi debitada corretamente");
        }

Neste método criamos uma instância da ContaBancaria com um saldo inicial (11.99) e então realizamos um saque (debito) de um valor válido (4.55).

A seguir usamos o método AreEqual da classe Assert para verificar que o saldo final esperado esta correto.

Nota: A classe Assert é usada para confirmar se os casos de testes estão produzindo o resultado esperado ou não usando métodos auxiliares como AreEqual() ou AreNotEqual().

AreEqual
Assume que dois valores são iguais (ou não).
Geralmente é usado para verificar o valor de retorno de um método em relação ao valor esperado.

Por exemplo, você poderia usar esse método com um método que adiciona dois números:

Assert.AreEqual (calc.Add (1,1), 2)  

Se o valor de retorno de calc.Add (1,1) é 2, então o teste passa.

Lembrando que um método de teste precisa seguir os seguintes requisitos:

Executando o teste unitário

No menu Build clique em Build Solution.

Se não existir nenhum erro a janela UnitTestExplorer vai aparecer com o método o Debito_ComValorValido_AtualizaSaldo listado no grupo Not Run Tests.

Se o Test Explorer não aparecer depois do Build; no menu Test clique em Windows e a seguir em Test Explorer.

Escolha a opção Run All para executar o teste.

Enquanto o teste estiver sendo executado a barra de status no topo da janela vai cintilar oscilando a sua cor.

Ao final da execução, a barra se torna verde se todos os testes passaram, ou vermelha se algum teste falhou.

No nosso caso o teste falhou. O método de teste é movido para o grupo Failed Tests.

Selecione o método no Test Explorer para ver os detalhes na base da janela:

O resultado do teste contém a mensagem que descreve a falha.

Para o método AreEquals, a mensagem exibe que era esperado uma diferença não maior que <0,001> entre o valor esperado <7,44> e o valor atual <16,54>.

Estávamos esperando que o saldo diminuísse partir do saldo inicial, mas em vez disso ele aumentou no valor do débito.

Um reexame do código do método Debito() mostra que o teste de unidade conseguiu encontrar um bug. O valor do saque esta sendo adicionado ao saldo da conta quando deveria ser subtraído.

Corrigindo o bug

Para corrigir o bug basta alterar o código do método Debito() para subtrair o valor do saque do saldo conforme abaixo:

       public void Debito(double valor)
        {
            if (bloqueada)
            {
                throw new Exception("Conta Bloqueada");
            }
            if (valor > saldo)
            {
                throw new ArgumentOutOfRangeException("valor maior que o saldo");
            }
            if (valor < 0)
            {
                throw new ArgumentOutOfRangeException("valor menor que zero");
            }
            saldo -= valor; // código com erro corrigido
       }

Executando os testes novamente iremos obter :

Na janela Test Explorer clique em Run All.

Veremos que a barra se torna verde e o teste é movido para o grupo Passsed Tests.

Pegue o projeto completo aqui : Banco.zip

Meus filhinhos, não amemos de palavra, nem de língua, mas por obra e em verdade.
E nisto conhecemos que somos da verdade, e diante dele asseguraremos nossos corações;
Sabendo que, se o nosso coração nos condena, maior é Deus do que o nosso coração, e conhece todas as coisas.
1 João 3:18-20

Referências:


José Carlos Macoratti