34
Guia Básico de TDD em C#.Net Versão do template 1.0 Confidencial DBServer, 2016 Página 1 de 34 Guia Básico de TDD em C#.Net

TDD Guia Basico - DBServer Assessoria em Sistemas de ... · Guia Básico de TDD em C#.Net Versão do template 1.0 Confidencial DBServer, 2016 Página 7 de 34 Ao tentar rodar este

  • Upload
    others

  • View
    6

  • Download
    0

Embed Size (px)

Citation preview

Page 1: TDD Guia Basico - DBServer Assessoria em Sistemas de ... · Guia Básico de TDD em C#.Net Versão do template 1.0 Confidencial DBServer, 2016 Página 7 de 34 Ao tentar rodar este

Guia Básico de TDD em C#.Net Versão do template

1.0

Confidencial DBServer, 2016 Página 1 de 34

Guia Básico de TDD em C#.Net

Page 2: TDD Guia Basico - DBServer Assessoria em Sistemas de ... · Guia Básico de TDD em C#.Net Versão do template 1.0 Confidencial DBServer, 2016 Página 7 de 34 Ao tentar rodar este

Guia Básico de TDD em C#.Net Versão do template

1.0

Confidencial DBServer, 2016 Página 2 de 34

Índice 1. Introdução 3

2. Definições 3

3. Exemplo básico 4

3.1 Criação do Projeto de Teste 4 3.2 Criação dos primeiros testes 6 3.3 Refatoração do código 12

4. Tipos de Assert 19

4.1 Assert.AreEqual 19 4.2 Assert.AreNotEqual 20 4.3 Assert.AreSame 20 4.4 Assert.AreNotSame 20 4.5 Assert.Fail 21 4.6 Assert.Inconclusive 21 4.7 Assert.IsTrue 21 4.8 Assert.IsFalse 22 4.9 Assert.IsInstanceOfType 22 4.10 Assert.IsNotInstanceOfType 22 4.11 Assert.IsNull 22 4.12 Assert.IsNotNull 22

5. Tipos de CollectionAssert 23

5.1 CollectionAssert.AreEqual 23 5.2 CollectionAssert.AreNotEqual 23 5.3 CollectionAssert.AllItemsAreUnique 23 5.4 CollectionAssert.Contains 23 5.5 CollectionAssert.DoesNotContain 24 Oposto de CollectionAssert.Contains. Erro! Indicador não definido. 5.6 CollectionAssert.ReferenceEquals 24 5.7 CollectionAssert.AllItemsAreNotNull 24 5.8 CollectionAssert.AllItemsAreInstancesOfType 24 5.9 CollectionAssert.IsSubsetOf 25 5.10 CollectionAssert.IsNotSubsetOf 25 Oposto de CollectionAssert.IsSubsetOf 25

6. ExpectedException 26

7. Nunit Framework 27

7.1 Instalação e configuração 27 7.2 Executando testes no Nunit 30

8. Fontes 34

Page 3: TDD Guia Basico - DBServer Assessoria em Sistemas de ... · Guia Básico de TDD em C#.Net Versão do template 1.0 Confidencial DBServer, 2016 Página 7 de 34 Ao tentar rodar este

Guia Básico de TDD em C#.Net Versão do template

1.0

Confidencial DBServer, 2016 Página 3 de 34

1. Introdução

Este documento tem por finalidade apresentar o básico da metodologia TDD, bem como

exemplos de sua utilização.

2. Definições

TDD (Test Driven Development) é uma técnica que surgiu com o objetivo de produzir código

confiável em menos tempo e com menos defeitos.

No método tradicional de desenvolvimento o código é testado apenas no final da codificação,

fazendo com que o desenvolvedor encontre muitos erros e necessite muito tempo debugando todo o

código para tentar encontrar a razão e solucionar o problema e, frequentemente, encontrando novos

erros resultantes da última correção realizada.

O TDD, no entanto, traz uma nova abordagem: Teste primeiro, codifique depois. Ele se baseia

no ciclo Vermelho-Verde-Refatora, que seria resumidamente:

1) Crie testes que garantam que o código funcione adequadamente. Como apenas os testes

foram criados e nada foi codificado, os testes já iniciarão falhos. (Vermelho)

2) Após criar o teste, crie o código necessário para que o teste passe da forma mais simples

possível e rode o teste novamente. (Verde)

3) Se o código passar no teste, então refatore o código aplicando boas práticas para torna-lo

mais testável e repita o processo novamente. (Refatora)

Vantagens:

Código é testado constantemente, desde o início do projeto e não apenas no final. Erros

são encontrados e resolvidos em sua origem.

Para que o código seja testável, ele deve ser bem codificado, incentivando boas práticas

de programação e forçando o desenvolvedor a usar seu raciocíno de forma mais elevada

para evitar acoplamentos e dependências.

Segurança para o desenvolvedor que sabe que qualquer erro será encontrado logo no

início do desenvolvimento.

Facilita a refatoração do código.

Pode ser usado como documentação.

Desvantagens:

Desenvolvimento inicial mais lento, até desenvolvedor se adaptar a técnica.

Necessidade de manutenção dos códigos de teste, além do código de produção.

Page 4: TDD Guia Basico - DBServer Assessoria em Sistemas de ... · Guia Básico de TDD em C#.Net Versão do template 1.0 Confidencial DBServer, 2016 Página 7 de 34 Ao tentar rodar este

Guia Básico de TDD em C#.Net Versão do template

1.0

Confidencial DBServer, 2016 Página 4 de 34

3. Exemplo básico

Como projeto de exemplo usaremos um projeto muito simples para a construção de um carro,

que deverá seguir as seguintes regras de negócio:

Deve possuir um motor

Deve possuir duas portas

Deve possuir quatro rodas

3.1 Criação do Projeto de Teste

Crie um projeto do tipo Class Library no Visual Studio. Eu nomeei meu projeto como TDD.Domain.

Page 5: TDD Guia Basico - DBServer Assessoria em Sistemas de ... · Guia Básico de TDD em C#.Net Versão do template 1.0 Confidencial DBServer, 2016 Página 7 de 34 Ao tentar rodar este

Guia Básico de TDD em C#.Net Versão do template

1.0

Confidencial DBServer, 2016 Página 5 de 34

Crie um novo projeto do tipo Test / Unit Test Project no Visual Studio. Eu nomeei meu projeto como

TDD.Test:

Criado o projeto, adicione referência ao projeto TDD.Domain no projeto TDD.Test:

Page 6: TDD Guia Basico - DBServer Assessoria em Sistemas de ... · Guia Básico de TDD em C#.Net Versão do template 1.0 Confidencial DBServer, 2016 Página 7 de 34 Ao tentar rodar este

Guia Básico de TDD em C#.Net Versão do template

1.0

Confidencial DBServer, 2016 Página 6 de 34

3.2 Criação dos primeiros testes

Baseando-se nas regras de negócio básicas, já podemos iniciar o desenvolvimento utilizando a

metodologia TDD. Primeiro passo será a criação dos testes.

Iniciaremos verificando se o carro possui um motor criando o método de teste

DevePossuirMotor(), instanciando um objeto do tipo Carro e testando se o atributo Motor é vazio:

Teste inicial

/// <summary> /// Valida se atributo Motor da classe Carro não é nulo /// </summary> [TestMethod] public void DevePossuirMotor() { Carro carro = new Carro(); Assert.IsNotNull(carro.Motor); }

Para rodar o teste, basta clicar com o botão direito sobre o método ou sobre o nome da classe

e selecionar Run Tests.

Page 7: TDD Guia Basico - DBServer Assessoria em Sistemas de ... · Guia Básico de TDD em C#.Net Versão do template 1.0 Confidencial DBServer, 2016 Página 7 de 34 Ao tentar rodar este

Guia Básico de TDD em C#.Net Versão do template

1.0

Confidencial DBServer, 2016 Página 7 de 34

Ao tentar rodar este teste, recebemos um erro de compilação pois a classe Carro não existe, mas isto

está correto pois a primeira etapa do TDD nos diz que devemos primeiro criar o teste e depois

codificarmos da forma mais simples possível para fazer o teste passar.

Então, vamos para a próxima etapa e iniciaremos a codificação de fato, criando a classe Carro e os

demais objetos necessários (neste caso a classe Motor) para este teste ser aceito:

Criação das classes

public class Motor { public double Potencia { get; set; } public string Combustivel { get; set; } public Motor() { } }

public class Carro { public Motor Motor { get; private set; } public Carro() { }

}

Sem o erro de compilação podemos rodar o teste, mas o teste irá falhar novamente já que o objeto

Motor não foi inicializado:

Page 8: TDD Guia Basico - DBServer Assessoria em Sistemas de ... · Guia Básico de TDD em C#.Net Versão do template 1.0 Confidencial DBServer, 2016 Página 7 de 34 Ao tentar rodar este

Guia Básico de TDD em C#.Net Versão do template

1.0

Confidencial DBServer, 2016 Página 8 de 34

Basta inicializarmos a propriedade Motor no construtor da classe Carro e testar novamente que o teste

passará:

Inicializando propriedade Public Carro() { Motor = new Motor(); }

Nosso próximo passo será criar testes para validar se o carro possui 4 rodas e 2 portas. Novamente aqui

os objetos Porta e Roda ainda não existem, bem como os atributos Portas e Rodas na classe Carro:

Criando testes de quantidade de Portas e Rodas

/// <summary> /// Valida se carro possui 4 rodas /// </summary> [TestMethod] public void DevePossuirQuatroRodas() { Carro carro = new Carro(); List<Roda> rodas = carro.Rodas; Assert.AreEqual( 4, rodas.Count ); } /// <summary> /// Valida se carro possui 2 portas /// </summary> [TestMethod] public void DevePossuirDuasPortas() { Carro carro = new Carro(); List<Porta> portas = carro.Portas; Assert.AreEqual( 2, portas.Count ); }

Page 9: TDD Guia Basico - DBServer Assessoria em Sistemas de ... · Guia Básico de TDD em C#.Net Versão do template 1.0 Confidencial DBServer, 2016 Página 7 de 34 Ao tentar rodar este

Guia Básico de TDD em C#.Net Versão do template

1.0

Confidencial DBServer, 2016 Página 9 de 34

Testes prontos, vamos ao segundo passo codificar novamente, criando as classes e propriedades que

foram identificadas no teste:

Criando classes e propriedades

public class Porta { public bool EstaAberta { get; set; } public Porta() { } }

public class Roda { public double Aro { get; set; } public Roda() { } }

public class Carro { private List<Roda> _rodas; private List<Porta> _portas; public Motor Motor { get; private set; } public Lataria Lataria { get; private set; } public List<Roda> Rodas { get { return _rodas; } } public List<Porta> Portas { get { return _portas; } } public Carro() { Motor = motor;

Page 10: TDD Guia Basico - DBServer Assessoria em Sistemas de ... · Guia Básico de TDD em C#.Net Versão do template 1.0 Confidencial DBServer, 2016 Página 7 de 34 Ao tentar rodar este

Guia Básico de TDD em C#.Net Versão do template

1.0

Confidencial DBServer, 2016 Página 10 de 34

Lataria = lataria; _portas = new List<Porta>(); _rodas = new List<Roda>(); } }

Ao executarmos o teste, obtivemos os erros abaixo, pois não incluímos nenhuma Porta ou Roda ao

nosso Carro:

Vamos incluir as portas e rodas em nosso carro, criando os métodos CriarPortas() e CriarRodas() e rodar

o teste novamente, desta vez o teste passará:

Incluindo portas e rodas no carro

public class Carro { private List<Roda> _rodas; private List<Porta> _portas; public Motor Motor { get; private set; } public Lataria Lataria { get; private set; } public List<Roda> Rodas { get { return _rodas; } } public List<Porta> Portas {

Page 11: TDD Guia Basico - DBServer Assessoria em Sistemas de ... · Guia Básico de TDD em C#.Net Versão do template 1.0 Confidencial DBServer, 2016 Página 7 de 34 Ao tentar rodar este

Guia Básico de TDD em C#.Net Versão do template

1.0

Confidencial DBServer, 2016 Página 11 de 34

get { return _portas; } } public Carro() { Motor = new Motor(); Lataria = new Lataria(); CriarRodas(); CriarPortas(); } private void CriarPortas() { _portas = new List<Porta>(); Porta portaDireita = new Porta(); Porta portaEsquerda = new Porta(); _portas.Add( portaDireita ); _portas.Add( portaEsquerda); } private void CriarRodas() { _rodas = new List<Roda>(); Roda rodaDianteiraDireita = new Roda(); Roda rodaDianteiraEsquerda = new Roda(); Roda rodaTraseiraDireita = new Roda(); Roda rodaTraseiraEsquerda = new Roda(); _rodas.Add( rodaDianteiraDireita ); _rodas.Add( rodaDianteiraEsquerda ); _rodas.Add( rodaTraseiraDireita ); _rodas.Add( rodaTraseiraEsquerda ); } }

Page 12: TDD Guia Basico - DBServer Assessoria em Sistemas de ... · Guia Básico de TDD em C#.Net Versão do template 1.0 Confidencial DBServer, 2016 Página 7 de 34 Ao tentar rodar este

Guia Básico de TDD em C#.Net Versão do template

1.0

Confidencial DBServer, 2016 Página 12 de 34

3.3 Refatoração do código

O terceiro princípio do TDD é a refatoração, tornar o código mais testável e, por consequência, tornar o

código menos acoplado e mais coeso.

Vamos então refatorar nosso código, iniciando pela criação de interfaces para cada um de nossos

objetos e modificando os tipos dos objetos para interfaces ao invés de classes concretas dentro da

classe Carro:

Criando interfaces

public interface IRoda { double Aro { get; set; } }

public interface IPorta { bool EstaAberta { get; set; } }

public interface ILataria { string Cor { get; set; } }

public interface IMotor { double Potencia { get; set; } string Combustivel { get; set; } }

public interface ICarro { IMotor Motor { get; set; } List<IRoda> Rodas { get; set; } List<IPorta> Portas { get; set; } ILataria Lataria { get; set; } }

Fazendo classes implementarem e usarem interfaces public class Roda : IRoda { public double Aro { get; set; } public Roda()

Page 13: TDD Guia Basico - DBServer Assessoria em Sistemas de ... · Guia Básico de TDD em C#.Net Versão do template 1.0 Confidencial DBServer, 2016 Página 7 de 34 Ao tentar rodar este

Guia Básico de TDD em C#.Net Versão do template

1.0

Confidencial DBServer, 2016 Página 13 de 34

{ }

}

public class Porta : IPorta { public bool EstaAberta { get; set; } public Porta() { }

}

public class Lataria : ILataria { public string Cor { get; set; } public Lataria() { } }

public class Motor : IMotor { public double Potencia { get; set; } public string Combustivel { get; set; } public Motor() { } }

public class Carro : ICarro { private List<IRoda> _rodas; private List<IPorta> _portas; public IMotor Motor { get; private set; } public ILataria Lataria { get; private set; } public List<IRoda> Rodas { get { return _rodas; }

Page 14: TDD Guia Basico - DBServer Assessoria em Sistemas de ... · Guia Básico de TDD em C#.Net Versão do template 1.0 Confidencial DBServer, 2016 Página 7 de 34 Ao tentar rodar este

Guia Básico de TDD em C#.Net Versão do template

1.0

Confidencial DBServer, 2016 Página 14 de 34

} public List<IPorta> Portas { get { return _portas; } } public Carro() { Motor = new Motor(); Lataria = new Lataria(); CriarRodas(); CriarPortas(); } private void CriarPortas() { _portas = new List<IPorta>(); IPorta portaDireita = new Porta(); IPorta portaEsquerda = new Porta(); _portas.Add( portaDireita ); _portas.Add( portaEsquerda); } private void CriarRodas() { _rodas = new List<IRoda>(); IRoda rodaDianteiraDireita = new Roda(); IRoda rodaDianteiraEsquerda = new Roda(); IRoda rodaTraseiraDireita = new Roda(); IRoda rodaTraseiraEsquerda = new Roda(); _rodas.Add( rodaDianteiraDireita ); _rodas.Add( rodaDianteiraEsquerda ); _rodas.Add( rodaTraseiraDireita ); _rodas.Add( rodaTraseiraEsquerda ); } }

Page 15: TDD Guia Basico - DBServer Assessoria em Sistemas de ... · Guia Básico de TDD em C#.Net Versão do template 1.0 Confidencial DBServer, 2016 Página 7 de 34 Ao tentar rodar este

Guia Básico de TDD em C#.Net Versão do template

1.0

Confidencial DBServer, 2016 Página 15 de 34

Nosso código agora usa interfaces. Vamos adaptar nossos testes para utiliza-las:

Aplicando interfaces em nosso teste

/// <summary> /// Valida se atributo Motor da classe Carro não é nulo /// </summary> [TestMethod] public void DevePossuirMotor() { ICarro carro = new Carro(); Assert.IsNotNull(carro.Motor); } /// <summary> /// Valida se carro possui 4 rodas /// </summary> [TestMethod] public void DevePossuirQuatroRodas() { ICarro carro = new Carro(); List<IRoda> rodas = carro.Rodas; Assert.AreEqual( 4, rodas.Count ); } /// <summary> /// Valida se carro possui 2 portas /// </summary> [TestMethod] public void DevePossuirDuasPortas() { ICarro carro = new Carro(); List<IPorta> portas = carro.Portas; Assert.AreEqual( 2, portas.Count ); }

Outra refatoração que temos que realizar aqui é aplicar os conceitos de Injeção de Dependência e

Inversão de Controle, que trazem algumas vantagens como:

Desacoplamento de nosso código, pois não é necessário modificar uma classe sempre

que uma de suas dependências for modificada.

Facilita a reutilização de código.

Torna o código testável.

Vamos aplicar estes conceitos em nossa classe Carro, incluindo no construtor da classe as

dependências Motor e Lataria. Desta forma, um Carro nunca poderá ser criado se não tiver um Motor e

Lataria e principalmente nunca será o responsável por decidir como o Motor e Lataria serão criados,

Page 16: TDD Guia Basico - DBServer Assessoria em Sistemas de ... · Guia Básico de TDD em C#.Net Versão do template 1.0 Confidencial DBServer, 2016 Página 7 de 34 Ao tentar rodar este

Guia Básico de TDD em C#.Net Versão do template

1.0

Confidencial DBServer, 2016 Página 16 de 34

essa responsabilidade será de quem criar o Carro. Outra vantagem é que um Carro poderá ser criado

com diversos motores e latarias sem precisar alterar sua implementação:

Aplicando Injeção de Dependência

public class Carro : ICarro { private List<IRoda> _rodas; private List<IPorta> _portas; public IMotor Motor { get; private set; } public ILataria Lataria { get; private set; } public List<IRoda> Rodas { get { return _rodas; } } public List<IPorta> Portas { get { return _portas; } } public Carro(IMotor motor, ILataria lataria) { Motor = motor; Lataria = lataria; CriarRodas(); CriarPortas(); } private void CriarPortas() { _portas = new List<IPorta>(); IPorta portaDireita = new Porta(); IPorta portaEsquerda = new Porta(); _portas.Add( portaDireita ); _portas.Add( portaEsquerda); } private void CriarRodas() { _rodas = new List<IRoda>(); IRoda rodaDianteiraDireita = new Roda();

Page 17: TDD Guia Basico - DBServer Assessoria em Sistemas de ... · Guia Básico de TDD em C#.Net Versão do template 1.0 Confidencial DBServer, 2016 Página 7 de 34 Ao tentar rodar este

Guia Básico de TDD em C#.Net Versão do template

1.0

Confidencial DBServer, 2016 Página 17 de 34

IRoda rodaDianteiraEsquerda = new Roda(); IRoda rodaTraseiraDireita = new Roda(); IRoda rodaTraseiraEsquerda = new Roda(); _rodas.Add( rodaDianteiraDireita ); _rodas.Add( rodaDianteiraEsquerda ); _rodas.Add( rodaTraseiraDireita ); _rodas.Add( rodaTraseiraEsquerda ); } }

Com a injeção de Dependência aplicada, agora o responsável por criar os objetos Motor e Lataria é

nosso método de teste:

Aplicando Injeção de Dependência em nosso teste

/// <summary> /// Valida se atributo Motor da classe Carro não é nulo /// </summary> [TestMethod] public void DevePossuirMotor() { IMotor motor = new Motor(); ILataria lataria = new Lataria(); ICarro carro = new Carro(motor, lataria); Assert.IsNotNull(carro.Motor); } /// <summary> /// Valida se carro possui 4 rodas /// </summary> [TestMethod] public void DevePossuirQuatroRodas() { IMotor motor = new MotorY(); ILataria lataria = new Lataria(); ICarro carro = new Carro(motor, lataria); List<IRoda> rodas = carro.Rodas; Assert.AreEqual( 4, rodas.Count ); } /// <summary> /// Valida se carro possui 2 portas /// </summary> [TestMethod] public void DevePossuirDuasPortas() { IMotor motor = new Motor(); ILataria lataria = new Lataria();

Page 18: TDD Guia Basico - DBServer Assessoria em Sistemas de ... · Guia Básico de TDD em C#.Net Versão do template 1.0 Confidencial DBServer, 2016 Página 7 de 34 Ao tentar rodar este

Guia Básico de TDD em C#.Net Versão do template

1.0

Confidencial DBServer, 2016 Página 18 de 34

ICarro carro = new Carro(motor, lataria); List<IPorta> portas = carro.Portas; Assert.AreEqual( 2, portas.Count ); }

Para melhor exemplificar o uso da Injeção de Dependência e Inversão de Controle criei a classe MotorY,

que também implementa a interface IMotor.

No método DevePossuirQuatroRodas() o Carro foi criado com o motor MotorY, enquanto que nos

métodos DevePossuirMotor() e DevePossuirDuasPortas() o Carro foi criado com o motor Motor,

não sendo necessário em nenhum momento alterar a implementação da classe Carro para cria-lo e

testa-lo com um motor diferente.

Page 19: TDD Guia Basico - DBServer Assessoria em Sistemas de ... · Guia Básico de TDD em C#.Net Versão do template 1.0 Confidencial DBServer, 2016 Página 7 de 34 Ao tentar rodar este

Guia Básico de TDD em C#.Net Versão do template

1.0

Confidencial DBServer, 2016 Página 19 de 34

4. Tipos de Assert

4.1 Assert.AreEqual

Verifica se dois valores são iguais.

Para o tipo string, o Assert.AreEqual possui os parâmetros ignoreCase e cultureInfo.

Para os tipos double e float o Assert.AreEqual possui o parâmetros delta.

Assert.AreEqual [TestMethod]

public void TestAssertEqual() { IMotor motor = new Motor(); ILataria lataria = new Lataria(); ICarro carro = new Carro( motor, lataria ); List<IPorta> portas = carro.Portas; Assert.AreEqual( 2, portas.Count, "Erro encontrado [{0}]", DateTime.Now );

}

/// <summary> /// Assert.AreEqual para tipo string /// </summary> [TestMethod] public void TestAssertEqualString() { string str1 = "Valor string"; string str2 = "Valor string"; //Sem mensagem formatada de Erro Assert.AreEqual( str1, str1 ); //Com IgnoreCase Assert.AreEqual( str1, str1, true ); //Com IgnoreCase Assert.AreEqual( str1, str1, true, System.Globalization.CultureInfo.GetCultureInfo(1) ); //Com mensagem formatada de Erro Assert.AreEqual( str1, str2, "Erro encontrado [{0}]", DateTime.Now ); //Completa Assert.AreEqual( str1, str1, true, System.Globalization.CultureInfo.GetCultureInfo( 1 ), "Erro encontrado [{0}]", DateTime.Now );

}

Page 20: TDD Guia Basico - DBServer Assessoria em Sistemas de ... · Guia Básico de TDD em C#.Net Versão do template 1.0 Confidencial DBServer, 2016 Página 7 de 34 Ao tentar rodar este

Guia Básico de TDD em C#.Net Versão do template

1.0

Confidencial DBServer, 2016 Página 20 de 34

/// <summary>

/// Assert.AreEqual para tipo double /// </summary> [TestMethod] public void TestAssertEqualDouble() { double dbl1 = 1.25; double dbl2 = 1.25; double delta = 0.5; //Sem mensagem formatada de Erro Assert.AreEqual( dbl1, dbl1 ); //Com delta Assert.AreEqual( dbl1, dbl1, delta ); //Com mensagem formatada de Erro Assert.AreEqual( dbl1, dbl2, "Erro encontrado [{0}]", DateTime.Now ); //Completa Assert.AreEqual( dbl1, dbl1, delta, "Erro encontrado [{0}]", DateTime.Now );

}

4.2 Assert.AreNotEqual

Oposto de AreEqual.

4.3 Assert.AreSame

Verifica se duas variaveis apontam para o mesmo objeto

Assert.AreSame [TestMethod]

public void TestAreSame() { IMotor motor = new Motor(); ILataria lataria = new Lataria(); //Sem mensagem formatada de Erro Assert.AreSame( motor, lataria); //Com mensagem formatada de Erro Assert.AreSame( motor, lataria, "Erro encontrado [{0}]", DateTime.Now ); }

4.4 Assert.AreNotSame

Oposto de AreSame.

Page 21: TDD Guia Basico - DBServer Assessoria em Sistemas de ... · Guia Básico de TDD em C#.Net Versão do template 1.0 Confidencial DBServer, 2016 Página 7 de 34 Ao tentar rodar este

Guia Básico de TDD em C#.Net Versão do template

1.0

Confidencial DBServer, 2016 Página 21 de 34

4.5 Assert.Fail

Sempre falha o teste sem validar nada.

Assert.Fail [TestMethod] public void TestFail() { //Sem mensagem formatada de Erro Assert.Fail(); //Com mensagem formatada de Erro Assert.Fail( "Erro encontrado [{0}]", DateTime.Now );

}

4.6 Assert.Inconclusive

Indica que o Assert não pode ser verificado

Assert.Inconclusive

[TestMethod] public void TestInconclusive() { //Sem mensagem formatada de Erro Assert.Inconclusive(); //Com mensagem formatada de Erro Assert.Inconclusive( "Erro encontrado [{0}]", DateTime.Now );

}

4.7 Assert.IsTrue

Valida se determinada condição é verdadeira

Assert.IsTrue [TestMethod] public void TestIsTrue() { string str1 = "Valor string"; string str2 = "Valor string"; //Sem mensagem formatada de Erro Assert.IsTrue( str1 == str2 ); //Com mensagem formatada de Erro Assert.IsTrue( str1 == str2, "Erro encontrado [{0}]", DateTime.Now );

}

Page 22: TDD Guia Basico - DBServer Assessoria em Sistemas de ... · Guia Básico de TDD em C#.Net Versão do template 1.0 Confidencial DBServer, 2016 Página 7 de 34 Ao tentar rodar este

Guia Básico de TDD em C#.Net Versão do template

1.0

Confidencial DBServer, 2016 Página 22 de 34

4.8 Assert.IsFalse

Oposto de IsTrue.

4.9 Assert.IsInstanceOfType

Valida se objeto é de determinado tipo

Assert.IsInstanceOfType [TestMethod] public void TestIsInstanceOf() { string str2 = "Valor string 2"; //Sem mensagem formatada de Erro Assert.IsInstanceOfType(str2, typeof(string)); //Com mensagem formatada de Erro Assert.IsInstanceOfType( str2, typeof( string ), "Erro encontrado [{0}]", DateTime.Now );

}

4.10 Assert.IsNotInstanceOfType

Oposto de IsInstanceOfType.

4.11 Assert.IsNull

Valida se valor é nulo

Assert.IsNull [TestMethod] public void TestIsNull() { string str2 = null; //Sem mensagem formatada de Erro Assert.IsNull(str2); //Com mensagem formatada de Erro Assert.IsNull( str2 , "Erro encontrado [{0}]", DateTime.Now );

}

4.12 Assert.IsNotNull

Oposto de IsNull

Page 23: TDD Guia Basico - DBServer Assessoria em Sistemas de ... · Guia Básico de TDD em C#.Net Versão do template 1.0 Confidencial DBServer, 2016 Página 7 de 34 Ao tentar rodar este

Guia Básico de TDD em C#.Net Versão do template

1.0

Confidencial DBServer, 2016 Página 23 de 34

5. Tipos de CollectionAssert

5.1 CollectionAssert.AreEqual

Valida se itens são os mesmos entre duas listas:

CollectionAssert.AreEqual [TestMethod] public void TestCollectionAreEqual() { List<string> first = new List<string>(); first.Add( "a" ); first.Add( "b" ); first.Add( "c" ); List<string> second = new List<string>(); second.Add( "a" ); second.Add( "b" ); second.Add( "c" ); //second.Add( "d" ); //Lista second tem um item a mais -> erro. CollectionAssert.AreEqual( first, second );

}

5.2 CollectionAssert.AreNotEqual

Oposto de CollectionAssert.AreEqual

5.3 CollectionAssert.AllItemsAreUnique

Valida se não existe nenhum valor duplicado em uma lista. Se algum item repetir, o teste falha:

CollectionAssert.AllItensAreUnique [TestMethod] public void TestCollectionAreUnique() { List<string> first = new List<string>(); first.Add( "a" ); first.Add( "b" ); first.Add( "c" ); //first.Add( "c" ); //Lista possui dos itens C -> erro. CollectionAssert.AllItemsAreUnique( first );

}

5.4 CollectionAssert.Contains

Valida se lista contém determinado item

CollectionAssert.Contains

Page 24: TDD Guia Basico - DBServer Assessoria em Sistemas de ... · Guia Básico de TDD em C#.Net Versão do template 1.0 Confidencial DBServer, 2016 Página 7 de 34 Ao tentar rodar este

Guia Básico de TDD em C#.Net Versão do template

1.0

Confidencial DBServer, 2016 Página 24 de 34

[TestMethod] public void TestCollectionAssertContains() { List<string> first = new List<string>(); first.Add( "a" ); first.Add( "b" ); first.Add( "c" ); CollectionAssert.Contains( first, "b" ); //CollectionAssert.Contains( first, "x" ); //Lista não contém x -> erro.

}

5.5 CollectionAssert.DoesNotContain

Oposto de CollectionAssert.Contains

5.6 CollectionAssert.ReferenceEquals

Valida se itens estão referenciando a mesma classe:

CollectionAssert.ReferenceEquals [TestMethod] public void TestCollectionReferencingSameClass() { List<string> lst1 = new List<string>(); List<string> lst2 = new List<string>(); CollectionAssert.ReferenceEquals( lst1, lst2 );

}

5.7 CollectionAssert.AllItemsAreNotNull

Valida se todos os itens não são nulos:

CollectionAssert.AllItemsAreNotNull [TestMethod] public void TestCollectonAllItensAreNotNull() { List<string> lst1 = new List<string>(); //lst1.Add( null ); //Valor nulo -> erro. lst1.Add( "a" ); lst1.Add( "b" ); CollectionAssert.AllItemsAreNotNull( lst1 );

}

5.8 CollectionAssert.AllItemsAreInstancesOfType

Valida se todos itens da lista são de determinado tipo:

Page 25: TDD Guia Basico - DBServer Assessoria em Sistemas de ... · Guia Básico de TDD em C#.Net Versão do template 1.0 Confidencial DBServer, 2016 Página 7 de 34 Ao tentar rodar este

Guia Básico de TDD em C#.Net Versão do template

1.0

Confidencial DBServer, 2016 Página 25 de 34

CollectionAssert.AllItemsAreInstanceOfType [TestMethod] public void TestCollectionAllItemsAreInstancesOfType() { List<object> lst1 = new List<object>(); lst1.Add( "a" ); lst1.Add( "b" ); //lst1.Add( 1 ); //Item não é string -> erro. CollectionAssert.AllItemsAreInstancesOfType( lst1, typeof( string ) );

}

5.9 CollectionAssert.IsSubsetOf

Valida se um conjunto de itens pertence a outra lista

CollectionAssert.IsSubsetOf [TestMethod] public void TestCollectionIsSubset() { List<string> lst1 = new List<string>(); lst1.Add( "a" ); lst1.Add( "b" ); lst1.Add( "c" ); lst1.Add( "d" ); List<string> lst2 = new List<string>(); lst2.Add( "a" ); lst2.Add( "b" ); //lst2.Add( "e" ); //Item 'e' não pertence a lst1 -> erro. CollectionAssert.IsSubsetOf( lst2, lst1 );

}

5.10 CollectionAssert.IsNotSubsetOf

Oposto de CollectionAssert.IsSubsetOf

Page 26: TDD Guia Basico - DBServer Assessoria em Sistemas de ... · Guia Básico de TDD em C#.Net Versão do template 1.0 Confidencial DBServer, 2016 Página 7 de 34 Ao tentar rodar este

Guia Básico de TDD em C#.Net Versão do template

1.0

Confidencial DBServer, 2016 Página 26 de 34

6. ExpectedException

É possível indicarmos para nosso teste que queremos receber uma excessão como resultado do teste e

faze-lo passar quando receber esta excessão.

Retornando ao nosso exemplo anterior, criei a classe Calculadora e dentro dela o método Dividir, que

divide dois valores e retorna um resultado. Porém, inclui neste método uma validação para retornar uma

excessão do tipo DividedByZeroException quando o divisor for igual a zero.

Nossa classe calculadora:

Calculadora public class Calculadora : ICalculadora { public double Dividir(double dividendo, double divisor) { if ( divisor == 0 ) throw new DivideByZeroException(); return dividendo / divisor; }

}

Nosso teste:

DeveRetornarException /// <summary> /// Valida se retornou exception /// </summary> [TestMethod] [ExpectedException(typeof(DivideByZeroException))] public void DeveRetornarException() { ICalculadora calculadora = new Calculadora(); double result = calculadora.Dividir( 10, 0 ); Assert.AreEqual( 0, result ); }

Perceba que abaixo do atributo [TestMethod]foi incluído o atributo

[ExpectedException(typeof(DivideByZeroException))], que indica que nosso método tem que

receber essa excessão como retorno do teste. Com isso, o teste passará ao receber esta excessão.

Page 27: TDD Guia Basico - DBServer Assessoria em Sistemas de ... · Guia Básico de TDD em C#.Net Versão do template 1.0 Confidencial DBServer, 2016 Página 7 de 34 Ao tentar rodar este

Guia Básico de TDD em C#.Net Versão do template

1.0

Confidencial DBServer, 2016 Página 27 de 34

7. Nunit Framework

A idéia desta sessão é demostrar que também é possível utilizar um framework de testes diferente da

solução nativa oferecida pelo Visual Studio, apresentando a instalação e realização dos mesmos testes

feitos anteriormente utilizando o Nunit framework.

7.1 Vantagens do Nunit Framework

A solução de testes do Visual Studio e o Nunit são muito semelhantes, mas podemos citar algumas

vantagens do Nunit:

Nunit tem uma interface gráfica própria onde basta associar a dll que deseja testar e realizar o

teste, permitindo que mais usuários possam realizar o teste sem a necessidade de possuir o

Visual Studio instalado.

Nunit tem atualizações mais constantes que o VisualStudio.

Nunit tem uma apresentação mais detalhada das excessões encontradas nos testes.

Nunit tem opções de Asserts.

7.2 Instalação e configuração

Crie um novo projeto do tipo ClassLibrary. Eu nomeei meu projeto como TDD.NunitTest. Adicione

referencia ao projeto TDD.Model.

Acesse a url http://nunit.org/?p=download e faça o download e a instalação do Nunit. Neste tutorial estou

utilizando a versão 2.6.4.

Page 28: TDD Guia Basico - DBServer Assessoria em Sistemas de ... · Guia Básico de TDD em C#.Net Versão do template 1.0 Confidencial DBServer, 2016 Página 7 de 34 Ao tentar rodar este

Guia Básico de TDD em C#.Net Versão do template

1.0

Confidencial DBServer, 2016 Página 28 de 34

Obs: Tive problemas instalando a versão 3.0.1, tive que desinstalar e instalar a 2.6.4 para conseguir

rodar. Caso o mesmo ocorra com você, é necessário instalar o Nunit via Package Manager Console ao

invés do Nuget Package, pois precisamos da versão 2.6.4 que é anterior. Caso o erro não ocorra, o

Nunit pode ser baixado normalmente pelo Manage Nuget Packages.

Instalação via Nuget:

No projeto de teste (no meu caso TDD.NunitTest), clique com o botão direito e então Manage Nuget

Packages:

Selecione Browse, pesquise por Nunit e então clique no botão Install, no canto superior direito:

Instalação pelo Package Console:

Page 29: TDD Guia Basico - DBServer Assessoria em Sistemas de ... · Guia Básico de TDD em C#.Net Versão do template 1.0 Confidencial DBServer, 2016 Página 7 de 34 Ao tentar rodar este

Guia Básico de TDD em C#.Net Versão do template

1.0

Confidencial DBServer, 2016 Página 29 de 34

Na janela que abrir, digite o comando abaixo para instalar a versão 2.6.4 do Nunit:

Page 30: TDD Guia Basico - DBServer Assessoria em Sistemas de ... · Guia Básico de TDD em C#.Net Versão do template 1.0 Confidencial DBServer, 2016 Página 7 de 34 Ao tentar rodar este

Guia Básico de TDD em C#.Net Versão do template

1.0

Confidencial DBServer, 2016 Página 30 de 34

Após finalizar a instação, podemos ver a referência adicionada ao nosso projeto:

7.3 Executando testes no Nunit

Nunit instalado, podemos codificar nosso teste.

Crie uma classe no projeto TDD.NunitTest e adicione o código abaixo. Estes são os mesmos métodos

utilizados anteriormente, porém adaptados para serem usados pelo Nunit, utilizando os atributos

[TestFixture] ao invés de [TestClass] e [Test] ao invés de [TestMethod].

Note também que possuimos dois métodos a mais aqui, decorados com os atributos [TestFixtureSetUp] e [TestFixtureTearDown].

O método decorado com [TestFixtureSetUp] sempre roda antes dos demais testes toda vez que qualquer teste da mesma classe é executado. Ele e é utilizado para inicializar configurações necessárias para o processo como um todo, como inicializar strings de conexões, por exemplo. O método decorado com [TestFixtureTearDown] sempre roda após os demais testes e é utilizado para

finalizar objetos, fechar conexões, etc.

Rode o teste da mesma forma anterior.

CarroTest com Nunit

Page 31: TDD Guia Basico - DBServer Assessoria em Sistemas de ... · Guia Básico de TDD em C#.Net Versão do template 1.0 Confidencial DBServer, 2016 Página 7 de 34 Ao tentar rodar este

Guia Básico de TDD em C#.Net Versão do template

1.0

Confidencial DBServer, 2016 Página 31 de 34

using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using NUnit.Framework; using TDD.Domain; namespace TDD.NunitTest { [TestFixture] public class CarroTest { private IMotor motor = null; private ILataria lataria = null; /// <summary> /// Este método sempre será executado ANTES dos testes /// </summary> [TestFixtureSetUp] public void StartTest() { motor = new Motor(); lataria = new Lataria(); } /// <summary> /// Este método sempre será executado APOS a execução dos testes /// </summary> [TestFixtureTearDown] public void EndTest() { motor = null; lataria = null; } /// <summary> /// Valida se atributo Motor da classe Carro não é nulo /// </summary> [Test] public void DevePossuirMotor() { //IMotor motor = new Motor(); //ILataria lataria = new Lataria(); ICarro carro = new Carro( motor, lataria ); Assert.IsNotNull( carro.Motor, "Motor é nulo {0} {1}!", "[X]", "[Y]" ); } /// <summary> /// Valida se carro possui 4 rodas /// </summary> [Test] public void DevePossuirQuatroRodas()

Page 32: TDD Guia Basico - DBServer Assessoria em Sistemas de ... · Guia Básico de TDD em C#.Net Versão do template 1.0 Confidencial DBServer, 2016 Página 7 de 34 Ao tentar rodar este

Guia Básico de TDD em C#.Net Versão do template

1.0

Confidencial DBServer, 2016 Página 32 de 34

{ //IMotor motor = new MotorY(); //ILataria lataria = new Lataria(); ICarro carro = new Carro( motor, lataria ); List<IRoda> rodas = carro.Rodas; Assert.AreEqual( 4, rodas.Count ); } /// <summary> /// Valida se carro possui 2 portas /// </summary> [Test] public void DevePossuirDuasPortas() { //IMotor motor = new Motor(); //ILataria lataria = new Lataria(); ICarro carro = new Carro( motor, lataria ); List<IPorta> portas = carro.Portas; Assert.AreEqual( 2, portas.Count ); } } }

Outra forma de utilizar o Nunit é usando o Nunit Application, que foi instalado anteriormente. Ele pode

ser encontrado em All Programs:

Ao abrir o programa, vá em File / Open Project e selecione a dll do nosso projeto TDD.NunitTest. O

Nunit ira carregar todos nossos métodos de teste:

Page 33: TDD Guia Basico - DBServer Assessoria em Sistemas de ... · Guia Básico de TDD em C#.Net Versão do template 1.0 Confidencial DBServer, 2016 Página 7 de 34 Ao tentar rodar este

Guia Básico de TDD em C#.Net Versão do template

1.0

Confidencial DBServer, 2016 Página 33 de 34

Clique em Run e ele executará todos os testes.

Page 34: TDD Guia Basico - DBServer Assessoria em Sistemas de ... · Guia Básico de TDD em C#.Net Versão do template 1.0 Confidencial DBServer, 2016 Página 7 de 34 Ao tentar rodar este

Guia Básico de TDD em C#.Net Versão do template

1.0

Confidencial DBServer, 2016 Página 34 de 34

8. Fontes

http://tableless.com.br/tdd-por-que-usar/

http://www.gonow.com.br/blog/2011/07/31/tech-talk-gonow-debate-pros-e-contras-do-tdd-e-do-bdd/

https://msdn.microsoft.com/en-us/library/microsoft.visualstudio.testtools.unittesting.assert.aspx

http://www.c-sharpcorner.com/UploadFile/dacca2/fundamental-of-unit-testing-understand-mock-object-in-

unit/

https://www.visualstudio.com/en-us/get-started/code/create-and-run-unit-tests-vs

Histórico da Revisão

Data Descrição Responsável

23/02/2016 Criação do arquivo Wagner De Rossi