Instruções passo a passo: criando e executando testes de unidade para código gerenciado
Este passo a passo guiará você por meio de criar, executar e personalizar uma série de testes de unidade usando o Microsoft unit test framework para código gerenciado e o Visual Studio Test Explorer.Comece com um projeto c# que está em desenvolvimento, crie testes que exercitem seu código, execute os testes e examinar os resultados.Você pode alterar o código do projeto e executar os testes novamente.
Este tópico contém as seções a seguir:
Crie um projeto de teste de unidade
Criar o primeiro método de teste
Corrija o código e executar novamente os testes
Usar testes de unidade para melhorar seu código
Observação |
---|
Este passo a passo usa o Microsoft unit test framework para código gerenciado.O Gerenciador de testes também pode executar testes de unidade de terceiros estruturas de teste que têm adaptadores para Gerenciador de testes.Para obter mais informações, consulte Como instalar estruturas de teste de unidade de terceiros |
Observação |
---|
Para obter informações sobre como executar testes de uma linha de comando, consulte Instruções passo a passo: usando o utilitário de teste de linha de comando. |
Pré-requisitos
- O projeto Bank.Consulte Projeto de exemplo para criação de testes de unidade.
Preparar o passo a passo
Abra o Visual Studio.
Sobre o arquivo aponte para novo e, em seguida, clique em projeto.
A caixa de diálogo Novo Projeto é exibida.
Em modelos instalados, clique em Visual C#.
Na lista de tipos de aplicativos, clique em biblioteca de classes.
No nome digite Bank e, em seguida, clique em OK.
Observação Se o nome "Bank" já for usado, escolha outro nome para o projeto.
O novo projeto Bank é criado e exibido no Gerenciador de soluções com o arquivo Class1. cs aberto no Editor de códigos.
Observação Se o arquivo Class1. cs não estiver aberto no Editor de códigos, duas vezes no arquivo Class1. cs no Solution Explorer para abri-lo.
Copie o código-fonte do Projeto de exemplo para criação de testes de unidade.
Substitua o conteúdo original de Class1. cs com o código de Projeto de exemplo para criação de testes de unidade.
Salve o arquivo como BankAccount.cs
No menu Compilar, clique em Compilar Solução.
Agora você tem um projeto chamado banco.Ele contém o código-fonte para teste e ferramentas para testá-lo.O namespace para o banco, BankAccountNS, contém a classe pública BankAccount, cujos métodos você testará nos procedimentos a seguir.
Este guia rápido, vamos nos concentrar no Debit método.O método Debit é chamado quando o dinheiro é retirado de uma conta e contém o código a seguir:
// method under test
public void Debit(double amount)
{
if(amount > m_balance)
{
throw new ArgumentOutOfRangeException("amount");
}
if (amount < 0)
{
throw new ArgumentOutOfRangeException("amount");
}
m_balance += amount;
}
Crie um projeto de teste de unidade
Pré-requisito: siga as etapas no procedimento, preparar o passo a passo.
Para criar um projeto de teste de unidade
Sobre o arquivo menu, escolha Adicionar, e, em seguida, escolha novo projeto....
Na caixa de diálogo Novo projeto, expanda instalados, expanda Visual C#, e, em seguida, escolha teste.
Na lista de modelos, selecione o projeto de teste de unidade.
No nome caixa, digite BankTest e, em seguida, escolha OK.
O BankTests projeto é adicionado ao o Bank solução.
No BankTests do projeto, adicione uma referência para o Bank solução.
No Solution Explorer, selecione referências no BankTests do projeto e escolha Adicionar referência... no menu de contexto.
Na caixa de diálogo Gerenciador de referências, expanda solução e verifique se o Bank item.
Criar a classe de teste
Precisamos de uma classe de teste para verificar a BankAccount classe.Podemos usar o Unittest1 foi gerado pelo modelo de projeto, mas deve dar ao arquivo e classe nomes mais descritivos.É possível fazer isso em uma única etapa, renomeando o arquivo no Solution Explorer.
Renomear um arquivo de classe
No Solution Explorer, selecione o arquivo Unittest1 CS no projeto BankTests.No menu de contexto, escolha Renomear, e, em seguida, renomeie o arquivo para BankAccountTests.cs.Escolha Sim na caixa de diálogo que pergunta se você deseja renomear todas as referências no projeto ao elemento de código 'UnitTest1'.Esta etapa altera o nome da classe para BankAccountTests.
O arquivo BankAccountTests.cs agora contém o seguinte código:
// unit test code
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace BankTests
{
[TestClass]
public class BankAccountTests
{
[TestMethod]
public void TestMethod1()
{
}
}
}
Adicionar um uso a instrução para o projeto de teste
Também podemos adicionar um usando a instrução para a classe para permitir que a chamada para o projeto de teste sem usar totalmente os nomes qualificados.Na parte superior do arquivo da classe, adicione:
using BankAccountNS;
Requisitos de classe de teste
Os requisitos mínimos para uma classe de teste são os seguintes:
O [TestClass] atributo é necessário código para qualquer classe que contém métodos de teste de unidade que você deseja executar no Gerenciador de testes na estrutura de testes de gerenciada de unidade de Microsoft.
Cada método de teste que você deseja executar com o Gerenciador de testes deve ter o [TestMethod]atributo.
Você pode ter outras classes em um projeto de teste de unidade que não têm o [TestClass] atributo e você pode ter outros métodos em classes de teste que não têm o [TestMethod] atributo.Você pode usar essas classes e métodos em seus métodos de teste.
Criar o primeiro método de teste
Neste procedimento, irá escrever métodos para verificar o comportamento do teste de unidade de Debit método o BankAccount classe.O método é listado acima.
Ao analisar o método sendo testado, determinamos que há pelo menos três comportamentos que precisam ser verificados:
O método lança um [ArgumentOutOfRangeException] se o valor do débito for maior que o saldo.
Ele também gera ArgumentOutOfRangeException se o valor do débito é menor que zero.
Se as verificações de 1.) e 2). forem atendidas, o método subtrai o valor do saldo de conta.
Em nosso primeiro teste, use um valor válido (aquele que for menor que o saldo da conta e maior que zero) retira a quantidade correta da conta.
Para criar um método de teste
Adicionar uma usando BankAccountNS; instrução no arquivo BankAccountTests.cs.
Adicione o seguinte método à BankAccountTests classe:
// unit test code [TestMethod] public void Debit_WithValidAmount_UpdatesBalance() { // arrange double beginningBalance = 11.99; double debitAmount = 4.55; double expected = 7.44; BankAccount account = new BankAccount("Mr. Bryan Walton", beginningBalance); // act account.Debit(debitAmount); // assert double actual = account.Balance; Assert.AreEqual(expected, actual, 0.001, "Account not debited correctly"); }
O método é bastante simple.Criamos um novo BankAccount com um saldo inicial do objeto e, em seguida, retirar um valor válido.Podemos usar o Microsoft unit test framework para código gerenciado AreEqual método para verificar se o saldo final é o que esperamos.
Requisitos do método de teste
Um método de teste deve atender aos seguintes requisitos:
O método deve ser decorado com o [TestMethod] atributo.
O método deve retornar void.
O método não pode ter parâmetros.
Compilar e executar o teste
Para compilar e executar o teste
No menu Compilar, escolha Compilar Solução.
Se houver erros, a janela UnitTestExplorer aparece com Debit_WithValidAmount_UpdatesBalance listadas no Not Run Tests grupo.Se o Gerenciador de testes não aparecer após uma compilação bem-sucedida, escolha teste no menu, escolha Windows, e, em seguida, escolha Gerenciador de testes.
Escolha Executar todos para executar o teste.Como a execução do teste da barra de status na parte superior da janela é animado.No final da execução do teste, a barra ativa se passam todos os métodos de teste de verde ou vermelho se algum dos testes falharem.
Nesse caso, o teste falhar.O método de teste é movido para o testes com falha.grupo.Selecione o método no Gerenciador de testes para exibir os detalhes na parte inferior da janela.
Corrija o código e executar novamente os testes
Analisar os resultados do teste
O resultado do teste contém uma mensagem que descreve a falha.Para o AreEquals método, exibe mensagem é esperada (o (**esperado <XXX>**parâmetro) e o que realmente foi recebido (o real <YYY> parâmetro).Estamos esperando o saldo para recusar do saldo inicial, mas em vez disso, ele aumentou a quantidade da retirada.
Um reexamination do código de débito mostra que o teste de unidade foi bem-sucedido em encontrar um bug.A quantidade da retirada é adicionada para o saldo da conta quando ele deve ser subtraído.
Corrigir o bug
Para corrigir o erro, simplesmente substitua a linha
m_balance += amount;
with
m_balance -= amount;
Execute novamente o teste
No Gerenciador de testes, escolha Executar todos para executar novamente o teste.A barra verde/vermelho ficará verde e o teste é movido para o testes aprovados grupo.
Usar testes de unidade para melhorar seu código
Esta seção descreve como um processo iterativo de análise, desenvolvimento de testes de unidade e refatoração pode ajudá-lo a tornar seu código de produção mais robusto e eficiente.
Analise os problemas
Depois de criar um método de teste para confirmar que um valor válido é corretamente deduzido o Debit método, podemos ativar para casos restantes em nossa análise original:
O método lança um ArgumentOutOfRangeException se o valor do débito for maior que o saldo.
Ele também gera ArgumentOutOfRangeException se o valor do débito é menor que zero.
Crie os métodos de teste
Uma primeira tentativa de criar um método de teste para solucionar esses problemas parece promissor:
//unit test method
[TestMethod]
[ExpectedException(typeof(ArgumentOutOfRangeException))]
public void Debit_WhenAmountIsLessThanZero_ShouldThrowArgumentOutOfRange()
{
// arrange
double beginningBalance = 11.99;
double debitAmount = -100.00;
BankAccount account = new BankAccount("Mr. Bryan Walton", beginningBalance);
// act
account.Debit(debitAmount);
// assert is handled by ExpectedException
}
Usamos o ExpectedExceptionAttribute atributo para afirmar que a exceção à direita foi lançada.O atributo faz com que o teste falhar, a menos que um ArgumentOutOfRangeException é lançada.Executando o teste com ambos os positivos e negativos debitAmount valores e modificando temporariamente o método sendo testado para lançar um genérico ApplicationException quando o valor for menor que zero demonstra esse teste funcione corretamente.Para testar o caso quando a quantidade retirada é maior que o saldo, tudo o que precisamos fazer é:
Criar um novo método de teste chamado Debit_WhenAmountIsMoreThanBalance_ShouldThrowArgumentOutOfRange.
Copiar o corpo do método de Debit_WhenAmountIsLessThanZero_ShouldThrowArgumentOutOfRange para o novo método.
Definir o debitAmount para um número maior que o saldo.
Executar testes
Executando os dois métodos com valores diferentes para debitAmount demonstra que os testes lidar adequadamente com os casos restantes.Executar todos os três testes confirmar que todos os casos em nossa análise original são abordados corretamente.
Continuar a análise
No entanto, os dois últimos métodos de teste também são um pouco preocupante.Nós não terá certeza de qual condição de código sob teste lança quando o teste é executado.Uma forma de diferenciar as duas condições seria útil.Como podemos pense sobre o problema mais, fica evidente que saber qual condição foi violada aumentaria nossa confiança nos testes.Essas informações também muito provavelmente seria útil para o mecanismo de produção que lida com a exceção quando ela é gerada pelo método sendo testado.Gerar mais informações quando o método lança ajudariam tudo em questão, mas o ExpectedException atributo não pode fornecer essas informações.
Observando novamente o método sendo testado, podemos ver as duas instruções condicionais usar um ArgumentOutOfRangeException construtor que usa o nome do argumento como um parâmetro:
throw new ArgumentOutOfRangeException("amount");
De uma pesquisa da biblioteca MSDN, descobrimos que um construtor existe com informações muito mais ricas.#ctor(String, Object, String) inclui o nome do argumento, o valor do argumento e uma mensagem definida pelo usuário.Podemos refatorar o método de teste para usar esse construtor.Melhor ainda, podemos usar membros de tipo disponíveis publicamente para especificar os erros.
Refatorar o código em teste
Primeiro, definimos duas constantes para as mensagens de erro no escopo da classe:
// class under test
public const string DebitAmountExceedsBalanceMessage = "Debit amount exceeds balance";
public const string DebitAmountLessThanZeroMessage = "Debit amount less than zero";
Vamos então modificar as duas instruções condicionais no Debit método:
// method under test
// ...
if (amount > m_balance)
{
throw new ArgumentOutOfRangeException("amount", amount, DebitAmountExceedsBalanceMessage);
}
if (amount < 0)
{
throw new ArgumentOutOfRangeException("amount", amount, DebitAmountLessThanZeroMessage);
}
// ...
Refatorar os métodos de teste
Em nosso método de teste, primeiro remova o ExpectedException atributo.Em seu lugar, podemos capturar a exceção lançada e verifique se que ela foi lançada na instrução de condição correta.No entanto, podemos agora deve decidir entre duas opções para verificar condições nossas restantes.Por exemplo, no Debit_WhenAmountIsMoreThanBalance_ShouldThrowArgumentOutOfRange método, é possível executar uma das seguintes ações:
Afirmar que o ActualValue propriedade da exceção (o segundo parâmetro do ArgumentOutOfRangeException construtor) é maior que o saldo inicial.Essa opção requer que testamos o ActualValue propriedade da exceção em relação a beginningBalance variável do método de teste e também requer e verificar se o ActualValue for maior que zero.
Afirmar que a mensagem (o terceiro parâmetro do construtor) inclui o DebitAmountExceedsBalanceMessage definido na BankAccount classe.
O StringAssert.Contains método na estrutura de teste de unidade da Microsoft nos permite verificar a segunda opção sem os cálculos necessários da primeira opção.
Uma segunda tentativa de revisão Debit_WhenAmountIsMoreThanBalance_ShouldThrowArgumentOutOfRange pode parecer com:
[TestMethod]
public void Debit_WhenAmountIsMoreThanBalance_ShouldThrowArgumentOutOfRange()
{
// arrange
double beginningBalance = 11.99;
double debitAmount = 20.0;
BankAccount account = new BankAccount("Mr. Bryan Walton", beginningBalance);
// act
try
{
account.Debit(debitAmount);
}
catch (ArgumentOutOfRangeException e)
{
// assert
StringAssert.Contains(e.Message, BankAccount. DebitAmountExceedsBalanceMessage);
}
}
Testar novamente, reconfiguração e analisá-lo novamente
Quando podemos testar novamente os métodos de teste com valores diferentes, encontramos os seguintes fatos:
Se podemos capturar o corrigir o erro usando uma declaração onde debitAmount maior que o saldo de Contains assert passa a exceção será ignorada e então o método de teste passa.Esse é o comportamento desejado.
Se usarmos um debitAmount é menor que 0, a declaração falhar porque a mensagem de erro será retornada.A declaração também falhará se apresentamos um temporário ArgumentOutOfRange exceção em outro ponto no método no caminho de código de teste.Isso também é bom.
Se o debitAmount valor é válido (ou seja, menos que o saldo mas maior que zero, nenhuma exceção é detectada, para que a declaração nunca é capturada.O método de teste é aprovado.Isso não é bom, pois queremos que o método de teste falhe se nenhuma exceção for lançada.
O fato de terceiro é um bug em nosso método de teste.Para tentar resolver o problema, adicionamos um Fail assert ao final do método de teste para manipular o caso em que nenhuma exceção é lançada.
Mas novos testes mostram que agora o teste falhará se a exceção correta é detectada.A instrução catch redefine a exceção e o método continua a ser executado, falhando no novo assert.Para resolver o problema de novo, adicionamos um return instrução após o StringAssert.Novos testes confirma que podemos corrigir os problemas.A versão final do Debit_WhenAmountIsMoreThanBalance_ShouldThrowArgumentOutOfRange parece com o seguinte:
[TestMethod]
public void Debit_WhenAmountIsMoreThanBalance_ShouldThrowArgumentOutOfRange()
{
// arrange
double beginningBalance = 11.99;
double debitAmount = 20.0;
BankAccount account = new BankAccount("Mr. Bryan Walton", beginningBalance);
// act
try
{
account.Debit(debitAmount);
}
catch (ArgumentOutOfRangeException e)
{
// assert
StringAssert.Contains(e.Message, BankAccount. DebitAmountExceedsBalanceMessage);
return;
}
Assert.Fail("No exception was thrown.");
}
Nesta seção final, o trabalho que fizemos a melhorar nosso código de teste levou a métodos de teste mais robusta e informativos.Mas o mais importante, a análise extra também levou à códigos melhores em nosso projeto sob teste.