SlideShare uma empresa Scribd logo
TDD em C++
Thiago Delgado Pinto
   Parte 1 – Verificação de Estado
   Parte 2 – Verificação de Comportamento
Verificação de Estado
YAFFUT_CHECK( ok );
YAFFUT_EQUAL( e, o );
YAFFUT_UNEQUAL( e, o );
YAFFUT_FAIL( msg );
YAFFUT_ASSERT_THROW( func, e );
   No Desenvolvimento Guiado por Testes, a
    corretude de um software é verificada
    através da escrita de testes para o mesmo.

   Nesses testes, verificamos se algo funciona
    conforme o esperado.

   Essa expectativa é o que devemos criar no
    teste.
   Uma expectativa é uma suposição sobre
    como algo funciona.

   Por exemplo:
    Se você quiser fazer uma função que some
    dois números naturais e retorne essa soma.
    Você pode supor que dados dois números, por
    exemplo, 1 e 2, a função retorne 3.
void somaDoisNumerosNaturaisCorretamente()
{                                            Nome do Teste
    assert( soma( 1, 2 ) == 3 );
}

         A função assert recebe um valor booleano.
         Se for true, a função não faz nada.
         Se for false, ela interrompe a execução do
         programa informando a linha em que houve a
         falha na afirmação.
void somaDoisNumerosInteirosCorretamente()
{
    assert( soma( -1, -1 ) == -2 );   Suposições devem
    assert( soma( -1, 0 ) == -1 );    tentar exercitar
                                      combinações com
    assert( soma( -1, 1 ) == 0 );     valores mínimos,
    assert( soma( 0, 0 ) == 0 );      máximos e
    assert( soma( 0, 1 ) == 1 );      potencialmente
                                      problemáticos.
    assert( soma( 1, 1 ) == 2 );
}
 Devemos, porém, dividir os casos em mais de
    um teste.
void somaUsandoNumerosNegativosCorretamente()
{
    assert( soma( -1, -1 ) == -2 );
    assert( soma( -1, 1 ) == 0 );
}
void somaComZeroResultaNoProprioNumero()
{
  assert( soma( -1, 0 ) == -1 );
  assert( soma( 0, 0 ) == 0 );
  assert( soma( 0, 1 ) == 1 );
}
void somaUsandoNumerosPositivosCorretamente()
{
  assert( soma( 1, 1 ) == 2 );
  assert( soma( 1, -1 ) == 0 );
}
void chuteAltoTiraUmDecimoDaEnergia()
{
    Lutador a, b;
    a.DefinirEnergia( 100 );
    b.DesferirChuteAltoEm( a );
    assert( a.Energia() == 90 );
}
void transferenciaFazDebitarDaContaOrigem()
{
    Conta origem, destino;
    origem.DefinirSaldo( 10500 );
    double valorATransferir = 500;
    double saldoEsperadoAposTransferencia =
      origem.Saldo() – valorATransferir;
    origem.Transferir( destino, valorATransferir );
    assert( origem.Saldo() ==
      saldoEsperadoAposTransferencia );
}
void transferenciaFazCreditarNaContaDestino()
{
    Conta origem, destino;
    origem.DefinirSaldo( 10500 );
    destino.DefinirSaldo( 2000 );
    double valorATransferir = 500;
    double saldoEsperadoAposTransferencia =
      destino.Saldo() + valorATransferir;
    origem.Transferir( destino, valorATransferir );
    assert( destino.Saldo() ==
      saldoEsperadoAposTransferencia );
}
   O nome deve tentar explicar o que é
    verificado e qual o resultado esperado.

   Nunca tente explicar como é verificado.

   O nome pode ser bem longo.

   Não se preocupe, você nunca precisará
    digitá-lo novamente. 
   ligarNitroFazCarroAcelerarQuandoEmMovimento ()

   acelerarComFreioDeMaoLigadoFazRodasTraseiras
    Derraparem()

   finalizarVendaFazBaixarEstoqueDeItensVendidos()

   cairNoPrecipicioRetiraVidaDoJogador()
   Precisamos criar um programa que chame todos
    os nossos testes.
   Há frameworks (bibliotecas de código que
    podem ser estendidas) que podemos usar para
    simplificar esse processo.
   Usando um framework, nosso main não irá
    precisar fazer nada além de iniciar o framework.
   O framework se encarregará de chamar os
    testes.
1/6



   Yet Another Framework For Unit Testing

   É opensource
   É portátil (Windows,GNU/Linux,MacOS,...)
   É pequeno
   É simples
   É poderoso

   http://members.home.nl/rutger.van.beusekom/
2/6


   Para usar o Yaffut, basta incluir seu único arquivo de código:
#include <yaffut.h>
   Criar uma classe (vazia) que servirá para agrupar os testes:
class TesteContaBancaria {};
   Use a macro TEST que recebe por parâmetro o nome da classe de
    teste e o nome do teste. Ex:
TEST( TesteContaBancaria,
    transferenciaFazDebitarDaContaOrigem )
{
  ...
}
3/6


   No lugar de assert, use YAFFUT_CHECK.
#include <yaffut.h>
class TesteContaBancaria {};
TEST( TesteContaBancaria, transferenciaFazDebitarDaContaOrigem )
{
  Conta origem, destino;
  origem.DefinirSaldo( 10500 );
    double valorATransferir = 500;
    double saldoEsperadoAposTransferencia =
      origem.Saldo() – valorATransferir;
    origem.Transferir( destino, valorATransferir );
    YAFFUT_CHECK( origem.Saldo() ==
     saldoEsperadoAposTransferencia );
}
4/6


   Porém, para comparar igualdades, prefira YAFFUT_EQUAL.
   Recebe dois parâmetros: valor esperado e valor obtido.

TEST( TesteContaBancaria,
  transferenciaFazDebitarDaContaOrigem )
{
  Conta origem, destino;
  origem.DefinirSaldo( 10500 );
    double valorATransferir = 500;
    double saldoEsperadoAposTransferencia =
      origem.Saldo() – valorATransferir;
    origem.Transferir( destino, valorATransferir );
    YAFFUT_EQUAL( saldoEsperadoAposTransferencia,
      origem.Saldo() );
}
5/6



   Outras funções:

YAFFUT_UNEQUAL( esperado, obtido )
YAFFUT_FAIL( mensagem )
YAFFUT_ASSERT_THROW( método, exceção )
6/6


   Como pode ser o programa principal de teste:
#include <yaffut.h>
#include “TesteContaBancaria.h”
// ... outras bibliotecas de teste
int main(int argc, const char* argv[])
{
  return yaffut::Factory::Instance().Main (argc,
   argv);
}
   CppUnit
   CppUnitLite
   boost::test
   TUT
   CxxTest
   ...
Verificação de Comportamento
MockRepository mr;
Intf *intf = mr.InterfaceMock< Intf >();
mr.ExpectCall( intf, Intf::Method1 )
 .With( “hello” )
 .Return( 10 );
AClass ac;
ac.DoSomething( *intf );
   TDD serve não só para verificar valores, mas,
    principalmente, para verificar o
    comportamento de objetos em suas
    interações com outros objetos.

   Para isso, criamos objetos substitutos,
    chamados de Mocks, que simulam a
    execução de métodos reais.
1/10



   Se ao fazer uma classe TerminalBancario
    quisermos ter um método que permita
    imprimir o extrato de uma conta bancária.

   Como testar se o extrato foi impresso ?
    (Só olhar o papel saindo, certo?)

   E se não tivermos impressora disponível para
    verificar ?
2/10



   Precisamos mesmo da impressora, ou
    podemos apenas simular o comportamento
    que se espera dela ?

   Se estamos interessados em seu
    comportamento, e não em sua
    implementação, podemos representar a
    impressora como uma interface.
3/10



class ImpressoraExtrato {
public:
   // Retorna true se conseguir imprimir
   bool Imprimir(const ContaBancaria
    &conta) = 0;
};
4/10


   Então, podemos pensar que nosso terminal
    bancário tenha o seguinte método:
// Retorna true se conseguir imprimir
bool TerminalBancario::ImprimirExtrato(
 const ContaBancaria &conta,
 const ImpressoraExtrato &impressora);
   Não importa como essa impressora funciona,
    desde que ela diga que imprimiu, para o terminal
    está OK.
5/10


   Daí, podemos criar uma implementação falsa da
    impressora, para ser nossa substituta da
    impressora real:
class ImpressoraExtratoFalsa : public
   ImpressoraExtrato
{
   bool Imprimir(const ContaBancaria &conta)
   {
     return true; // Só diz que imprimiu !
   }
};
6/10


   Nosso teste pode ficar assim:
TEST( TesteContaBancaria, terminalConsegueImprimirExtrato )
{
  ContaBancaria conta;
  conta.Depositar( 1000 );
  conta.Sacar( 500 );
    ImpressoraExtrato *impressora =
      new ImpressoraExtratoFalsa();
    TerminalBancario terminal;
    bool imprimiu = terminal.Imprimir(conta, *impressora );
    delete impressora;
    YAFFUT_CHECK( imprimiu );
}
7/10


   Mas como saber se o terminal interagiu
    corretamente com a impressora ?
   Sabemos apenas que a impressora foi passada
    como parâmetro, mas como saber se ela foi
    usada ?
   Ou seja, se o terminal chamou o método
    Imprimir como esperado (uma vez, passando a
    conta como parâmetro) e obteve um resultado
    dela ?
8/10



   Podemos, em implementação falsa, criar um
    controle para saber se o método foi chamado
    como esperado.

   E depois, no teste, verificamos se o método
    Imprimir foi chamado.
9/10


class ImpressoraExtratoFalsa : public ImpressoraExtrato
{
  ImpressoraExtratoFalsa() {
    chamadasAImprimir = 0;
  }
  bool Imprimir(const ContaBancaria &conta) {
    chamadasAImprimir++;
     return true;
  }
 int ChamadasAImprimir() const {
   return chamadasAImprimir;
 }
private:
   int chamadasAImprimir;
};
10/10


   Nosso teste pode ficar assim:
TEST( TesteContaBancaria, terminalConsegueImprimirExtrato )
{
  ContaBancaria conta;
  conta.Depositar( 1000 );
  conta.Sacar( 500 );
    ImpressoraExtrato *impressora =
      new ImpressoraExtratoFalsa();
    TerminalBancario terminal;
    bool imprimiu = terminal.Imprimir(conta, *impressora );
    YAFFUT_EQUAL( 1, impressora->ChamadasAImprimir() );
    YAFFUT_CHECK( imprimiu );
    delete impressora;
}
   Ter que criar manualmente implementações
    falsas (classes falsas) e contabilizar a execução
    de cada método é trabalhoso.
   Porém, há frameworks de teste que permitem a
    criação automática de implementações falsas
    (chamadas de Mocks), bastando apenas definir
    o comportamento esperado dos métodos.
   A contabilização da chamada também é feita
    automaticamente.
   Em C++ há bons frameworks de teste
        automatizado, porém, poucos com recursos de
        criação automática de mocks:
           Isolator++
           AMOP
           MockitoPP
           HippoMocks
           etc.

       Adotaremos o HippoMocks com Yaffut1.
1. Veja análise em http://devhints.blogspot.com/2010/11/bons-frameworks-c-para-criacao.html
   Feito usando Yaffut (já vem com ele).
   É opensource.
   É simples.
   É poderoso.
   É portátil.
   http://www.assembla.com/spaces/hippomocks
   Sua classe principal é MockRepository, que
    permite criar um repositório de objetos falsos
    (mocks).

   Permite criação de mocks através do método
    InterfaceMock.

   Permite definir expectativas através do
    método ExpectCall.
TEST( TesteContaBancaria, terminalConsegueImprimirExtrato )
{
  ContaBancaria conta;
  conta.Depositar( 1000 );
  conta.Sacar( 500 );

    MockRepository mr; // Repositório de mocks
    ImpressoraExtrato *impressora =
      mr.InterfaceMock< ImpressoraExtrato >(); // Cria um mock
    // Cria a expectativa
    mr.ExpectCall( impressora, ImpressoraExtrato::Imprimir )
      .With( conta )
      .Return( true );

    TerminalBancario terminal;
    bool imprimiu = terminal.Imprimir(conta, *impressora );
    YAFFUT_CHECK( imprimiu );
    delete impressora;
    // Não precisa verificar NADA.
    // O framework verifica se a expectativa criada foi atendida!
}
TEST( TesteBomba, atirarNumaBombaFazExplodiLa )
{
  MockRepository mr; // Repositório de objetos falsos
    // Bomba falsa
    Bomba *bomba = mr.InterfaceMock< Bomba >();
    // Expectativa do que deve acontecer com a bomba
    // ao ser acertada por um tiro
    mr.ExpectCall( bomba, Bomba::Explodir );

    Jogador jogador;
    Revolver revolver( 38 );
    jogador.SegurarObjeto( revolver );
    revolver.AtirarNoObjeto( bomba ); // Deve fazê-la explodir
}
TDD em C++
Thiago Delgado Pinto

Mais conteúdo relacionado

PDF
Programando em python excecoes
PDF
Estrutura de linguagem C++
PPT
Algoritmos Aula 08
PDF
Pseudocódigo - Estrutura de Repetição (Lógica de Programação)
PDF
Aula6 - Linguagem C
PDF
Apostila c
PPT
Linguagens de Programação II - Aula 3
Programando em python excecoes
Estrutura de linguagem C++
Algoritmos Aula 08
Pseudocódigo - Estrutura de Repetição (Lógica de Programação)
Aula6 - Linguagem C
Apostila c
Linguagens de Programação II - Aula 3

Mais procurados (20)

PPTX
Aula 04 Estruturas de repetição 02 - Para Faça
PDF
mod3-programação-estruturada
PDF
Curso de Shell Script 10/11
PDF
Algoritmos resolvidos lista 2
PDF
Algoritmos e Programação: Estruturas de repetição
PDF
Algoritmos e lp parte3-pseudocódigo
PDF
Estruturas de Repetição - FOR, WHILE e DO WHILE
PPTX
Introdução ao php
PDF
Minicurso php
PDF
Manual-de-php
PPTX
Algoritmos - Comandos de Repetição
PDF
M5-Desenvolvimento-Paginas-Web
PDF
Comandos de Controle de Programa em C
DOCX
Comandos de controle de fluxo do php
PPTX
8a. aula -_estrutura_de_controle_de_repeticao_-_while_java
PDF
Exercicios sequenciais
PPT
Algoritmos Aula 09
PDF
Controle de Fluxo, Exceções, Assertivas
Aula 04 Estruturas de repetição 02 - Para Faça
mod3-programação-estruturada
Curso de Shell Script 10/11
Algoritmos resolvidos lista 2
Algoritmos e Programação: Estruturas de repetição
Algoritmos e lp parte3-pseudocódigo
Estruturas de Repetição - FOR, WHILE e DO WHILE
Introdução ao php
Minicurso php
Manual-de-php
Algoritmos - Comandos de Repetição
M5-Desenvolvimento-Paginas-Web
Comandos de Controle de Programa em C
Comandos de controle de fluxo do php
8a. aula -_estrutura_de_controle_de_repeticao_-_while_java
Exercicios sequenciais
Algoritmos Aula 09
Controle de Fluxo, Exceções, Assertivas
Anúncio

Destaque (13)

PDF
Ace tutorial c
PPT
Event Driven Architecture &amp; Complex Event Processing
DOCX
Act#28d 101 m
PDF
ApacheHadoop2xDeveloperJava
PPTX
PDF
Calendario Viernes 12 Febrero 2016
PPTX
Triángulos del cuello
PPTX
Import trade
PDF
Dossier de Proyectos de Grupo Shinè
PPT
Історія народу в пісні
PDF
登山 健康
PPTX
Light the Night Raises Funds for Blood-Cancer Research
Ace tutorial c
Event Driven Architecture &amp; Complex Event Processing
Act#28d 101 m
ApacheHadoop2xDeveloperJava
Calendario Viernes 12 Febrero 2016
Triángulos del cuello
Import trade
Dossier de Proyectos de Grupo Shinè
Історія народу в пісні
登山 健康
Light the Night Raises Funds for Blood-Cancer Research
Anúncio

Semelhante a TDD em C++ (20)

PDF
Test-driven Development
PDF
Desenvolvimento Dirigido por Testes com Junit
PDF
Atividades de Teste e Cobertura de Código em Java
PDF
Padrões para Desenvolvimento de Software Guiado por Testes
PPTX
TDD (Resumo)
PDF
Testes de Unidade com JUnit
PDF
TDD com Python (Completo)
PPTX
Introdução a testes unitários com jUnit
PPT
Apresentação de TDD na Fatec Jundiaí
PPTX
1 2 3 - Testando - Automatizando os testes de software
PPTX
Introdução a tdd
PPTX
Paletra sobre TDD, ocorrida no #DevDojo
PDF
UnP Eng. Software - Aula 28
PDF
Minicurso - Técnicas de Teste e Automatização do Teste de Unidade XII SemanaT...
PPT
Introdução a testes unitários automatizados com JUnit e NUnit
PPTX
TDD em 220V
PDF
Testes de Unidade com JUnit
PDF
Desenvolvimento em .Net - Testes Unitários
Test-driven Development
Desenvolvimento Dirigido por Testes com Junit
Atividades de Teste e Cobertura de Código em Java
Padrões para Desenvolvimento de Software Guiado por Testes
TDD (Resumo)
Testes de Unidade com JUnit
TDD com Python (Completo)
Introdução a testes unitários com jUnit
Apresentação de TDD na Fatec Jundiaí
1 2 3 - Testando - Automatizando os testes de software
Introdução a tdd
Paletra sobre TDD, ocorrida no #DevDojo
UnP Eng. Software - Aula 28
Minicurso - Técnicas de Teste e Automatização do Teste de Unidade XII SemanaT...
Introdução a testes unitários automatizados com JUnit e NUnit
TDD em 220V
Testes de Unidade com JUnit
Desenvolvimento em .Net - Testes Unitários

Mais de thiagodp (6)

PDF
Coding Dojo - Conceitos
PDF
Coding Dojo - Funcionamento
PDF
CEFET Coding Dojo - Divulgação
PDF
CEFET Coding Dojo - Desafios
PDF
DOJO - TDD com C++
PDF
I CEFET Coding Dojo - Divulgação
Coding Dojo - Conceitos
Coding Dojo - Funcionamento
CEFET Coding Dojo - Divulgação
CEFET Coding Dojo - Desafios
DOJO - TDD com C++
I CEFET Coding Dojo - Divulgação

Último (19)

PPTX
Programação - Linguagem C - Variáveis, Palavras Reservadas, tipos de dados, c...
PDF
Processos na gestão de transportes, TM100 Col18
PDF
Aula04-Academia Heri- Tecnologia Geral 2025
PPTX
BANCO DE DADOS - AULAS INICIAIS-sgbd.pptx
PDF
COBITxITIL-Entenda as diferença em uso governança TI
PDF
Apple Pippin Uma breve introdução. - David Glotz
PDF
Fullfilment AI - Forum ecommerce 2025 // Distrito e Total Express
PDF
Fundamentos de gerenciamento de ordens e planejamento no SAP TransportationMa...
PDF
Gestão de transportes básica no SAP S/4HANA, S4611 Col20
PPTX
Informática Aplicada Informática Aplicada Plano de Ensino - estudo de caso NR...
PDF
Custos e liquidação no SAP Transportation Management, TM130 Col18
PDF
Custos e faturamento no SAP S/4HANA Transportation Management, S4TM3 Col26
PDF
Mergulho profundo técnico para gestão de transportes no SAP S/4HANA, S4TM6 Col14
PPTX
Aula 18 - Manipulacao De Arquivos python
PPTX
Aula16ManipulaçãoDadosssssssssssssssssssssssssssss
PDF
Otimizador de planejamento e execução no SAP Transportation Management, TM120...
PDF
20250805_ServiceNow e a Arquitetura Orientada a Serviços (SOA) A Base para Ap...
PPTX
Como-se-implementa-um-softwareeeeeeeeeeeeeeeeeeeeeeeee.pptx
PPTX
Gestao-de-Bugs-em-Software-Introducao.pptxxxxxxxx
Programação - Linguagem C - Variáveis, Palavras Reservadas, tipos de dados, c...
Processos na gestão de transportes, TM100 Col18
Aula04-Academia Heri- Tecnologia Geral 2025
BANCO DE DADOS - AULAS INICIAIS-sgbd.pptx
COBITxITIL-Entenda as diferença em uso governança TI
Apple Pippin Uma breve introdução. - David Glotz
Fullfilment AI - Forum ecommerce 2025 // Distrito e Total Express
Fundamentos de gerenciamento de ordens e planejamento no SAP TransportationMa...
Gestão de transportes básica no SAP S/4HANA, S4611 Col20
Informática Aplicada Informática Aplicada Plano de Ensino - estudo de caso NR...
Custos e liquidação no SAP Transportation Management, TM130 Col18
Custos e faturamento no SAP S/4HANA Transportation Management, S4TM3 Col26
Mergulho profundo técnico para gestão de transportes no SAP S/4HANA, S4TM6 Col14
Aula 18 - Manipulacao De Arquivos python
Aula16ManipulaçãoDadosssssssssssssssssssssssssssss
Otimizador de planejamento e execução no SAP Transportation Management, TM120...
20250805_ServiceNow e a Arquitetura Orientada a Serviços (SOA) A Base para Ap...
Como-se-implementa-um-softwareeeeeeeeeeeeeeeeeeeeeeeee.pptx
Gestao-de-Bugs-em-Software-Introducao.pptxxxxxxxx

TDD em C++

  • 1. TDD em C++ Thiago Delgado Pinto
  • 2. Parte 1 – Verificação de Estado  Parte 2 – Verificação de Comportamento
  • 3. Verificação de Estado YAFFUT_CHECK( ok ); YAFFUT_EQUAL( e, o ); YAFFUT_UNEQUAL( e, o ); YAFFUT_FAIL( msg ); YAFFUT_ASSERT_THROW( func, e );
  • 4. No Desenvolvimento Guiado por Testes, a corretude de um software é verificada através da escrita de testes para o mesmo.  Nesses testes, verificamos se algo funciona conforme o esperado.  Essa expectativa é o que devemos criar no teste.
  • 5. Uma expectativa é uma suposição sobre como algo funciona.  Por exemplo: Se você quiser fazer uma função que some dois números naturais e retorne essa soma. Você pode supor que dados dois números, por exemplo, 1 e 2, a função retorne 3.
  • 6. void somaDoisNumerosNaturaisCorretamente() { Nome do Teste assert( soma( 1, 2 ) == 3 ); } A função assert recebe um valor booleano. Se for true, a função não faz nada. Se for false, ela interrompe a execução do programa informando a linha em que houve a falha na afirmação.
  • 7. void somaDoisNumerosInteirosCorretamente() { assert( soma( -1, -1 ) == -2 ); Suposições devem assert( soma( -1, 0 ) == -1 ); tentar exercitar combinações com assert( soma( -1, 1 ) == 0 ); valores mínimos, assert( soma( 0, 0 ) == 0 ); máximos e assert( soma( 0, 1 ) == 1 ); potencialmente problemáticos. assert( soma( 1, 1 ) == 2 ); }  Devemos, porém, dividir os casos em mais de um teste.
  • 8. void somaUsandoNumerosNegativosCorretamente() { assert( soma( -1, -1 ) == -2 ); assert( soma( -1, 1 ) == 0 ); } void somaComZeroResultaNoProprioNumero() { assert( soma( -1, 0 ) == -1 ); assert( soma( 0, 0 ) == 0 ); assert( soma( 0, 1 ) == 1 ); } void somaUsandoNumerosPositivosCorretamente() { assert( soma( 1, 1 ) == 2 ); assert( soma( 1, -1 ) == 0 ); }
  • 9. void chuteAltoTiraUmDecimoDaEnergia() { Lutador a, b; a.DefinirEnergia( 100 ); b.DesferirChuteAltoEm( a ); assert( a.Energia() == 90 ); }
  • 10. void transferenciaFazDebitarDaContaOrigem() { Conta origem, destino; origem.DefinirSaldo( 10500 ); double valorATransferir = 500; double saldoEsperadoAposTransferencia = origem.Saldo() – valorATransferir; origem.Transferir( destino, valorATransferir ); assert( origem.Saldo() == saldoEsperadoAposTransferencia ); }
  • 11. void transferenciaFazCreditarNaContaDestino() { Conta origem, destino; origem.DefinirSaldo( 10500 ); destino.DefinirSaldo( 2000 ); double valorATransferir = 500; double saldoEsperadoAposTransferencia = destino.Saldo() + valorATransferir; origem.Transferir( destino, valorATransferir ); assert( destino.Saldo() == saldoEsperadoAposTransferencia ); }
  • 12. O nome deve tentar explicar o que é verificado e qual o resultado esperado.  Nunca tente explicar como é verificado.  O nome pode ser bem longo.  Não se preocupe, você nunca precisará digitá-lo novamente. 
  • 13. ligarNitroFazCarroAcelerarQuandoEmMovimento ()  acelerarComFreioDeMaoLigadoFazRodasTraseiras Derraparem()  finalizarVendaFazBaixarEstoqueDeItensVendidos()  cairNoPrecipicioRetiraVidaDoJogador()
  • 14. Precisamos criar um programa que chame todos os nossos testes.  Há frameworks (bibliotecas de código que podem ser estendidas) que podemos usar para simplificar esse processo.  Usando um framework, nosso main não irá precisar fazer nada além de iniciar o framework.  O framework se encarregará de chamar os testes.
  • 15. 1/6  Yet Another Framework For Unit Testing  É opensource  É portátil (Windows,GNU/Linux,MacOS,...)  É pequeno  É simples  É poderoso  http://members.home.nl/rutger.van.beusekom/
  • 16. 2/6  Para usar o Yaffut, basta incluir seu único arquivo de código: #include <yaffut.h>  Criar uma classe (vazia) que servirá para agrupar os testes: class TesteContaBancaria {};  Use a macro TEST que recebe por parâmetro o nome da classe de teste e o nome do teste. Ex: TEST( TesteContaBancaria, transferenciaFazDebitarDaContaOrigem ) { ... }
  • 17. 3/6  No lugar de assert, use YAFFUT_CHECK. #include <yaffut.h> class TesteContaBancaria {}; TEST( TesteContaBancaria, transferenciaFazDebitarDaContaOrigem ) { Conta origem, destino; origem.DefinirSaldo( 10500 ); double valorATransferir = 500; double saldoEsperadoAposTransferencia = origem.Saldo() – valorATransferir; origem.Transferir( destino, valorATransferir ); YAFFUT_CHECK( origem.Saldo() == saldoEsperadoAposTransferencia ); }
  • 18. 4/6  Porém, para comparar igualdades, prefira YAFFUT_EQUAL.  Recebe dois parâmetros: valor esperado e valor obtido. TEST( TesteContaBancaria, transferenciaFazDebitarDaContaOrigem ) { Conta origem, destino; origem.DefinirSaldo( 10500 ); double valorATransferir = 500; double saldoEsperadoAposTransferencia = origem.Saldo() – valorATransferir; origem.Transferir( destino, valorATransferir ); YAFFUT_EQUAL( saldoEsperadoAposTransferencia, origem.Saldo() ); }
  • 19. 5/6  Outras funções: YAFFUT_UNEQUAL( esperado, obtido ) YAFFUT_FAIL( mensagem ) YAFFUT_ASSERT_THROW( método, exceção )
  • 20. 6/6  Como pode ser o programa principal de teste: #include <yaffut.h> #include “TesteContaBancaria.h” // ... outras bibliotecas de teste int main(int argc, const char* argv[]) { return yaffut::Factory::Instance().Main (argc, argv); }
  • 21. CppUnit  CppUnitLite  boost::test  TUT  CxxTest  ...
  • 22. Verificação de Comportamento MockRepository mr; Intf *intf = mr.InterfaceMock< Intf >(); mr.ExpectCall( intf, Intf::Method1 ) .With( “hello” ) .Return( 10 ); AClass ac; ac.DoSomething( *intf );
  • 23. TDD serve não só para verificar valores, mas, principalmente, para verificar o comportamento de objetos em suas interações com outros objetos.  Para isso, criamos objetos substitutos, chamados de Mocks, que simulam a execução de métodos reais.
  • 24. 1/10  Se ao fazer uma classe TerminalBancario quisermos ter um método que permita imprimir o extrato de uma conta bancária.  Como testar se o extrato foi impresso ? (Só olhar o papel saindo, certo?)  E se não tivermos impressora disponível para verificar ?
  • 25. 2/10  Precisamos mesmo da impressora, ou podemos apenas simular o comportamento que se espera dela ?  Se estamos interessados em seu comportamento, e não em sua implementação, podemos representar a impressora como uma interface.
  • 26. 3/10 class ImpressoraExtrato { public: // Retorna true se conseguir imprimir bool Imprimir(const ContaBancaria &conta) = 0; };
  • 27. 4/10  Então, podemos pensar que nosso terminal bancário tenha o seguinte método: // Retorna true se conseguir imprimir bool TerminalBancario::ImprimirExtrato( const ContaBancaria &conta, const ImpressoraExtrato &impressora);  Não importa como essa impressora funciona, desde que ela diga que imprimiu, para o terminal está OK.
  • 28. 5/10  Daí, podemos criar uma implementação falsa da impressora, para ser nossa substituta da impressora real: class ImpressoraExtratoFalsa : public ImpressoraExtrato { bool Imprimir(const ContaBancaria &conta) { return true; // Só diz que imprimiu ! } };
  • 29. 6/10  Nosso teste pode ficar assim: TEST( TesteContaBancaria, terminalConsegueImprimirExtrato ) { ContaBancaria conta; conta.Depositar( 1000 ); conta.Sacar( 500 ); ImpressoraExtrato *impressora = new ImpressoraExtratoFalsa(); TerminalBancario terminal; bool imprimiu = terminal.Imprimir(conta, *impressora ); delete impressora; YAFFUT_CHECK( imprimiu ); }
  • 30. 7/10  Mas como saber se o terminal interagiu corretamente com a impressora ?  Sabemos apenas que a impressora foi passada como parâmetro, mas como saber se ela foi usada ?  Ou seja, se o terminal chamou o método Imprimir como esperado (uma vez, passando a conta como parâmetro) e obteve um resultado dela ?
  • 31. 8/10  Podemos, em implementação falsa, criar um controle para saber se o método foi chamado como esperado.  E depois, no teste, verificamos se o método Imprimir foi chamado.
  • 32. 9/10 class ImpressoraExtratoFalsa : public ImpressoraExtrato { ImpressoraExtratoFalsa() { chamadasAImprimir = 0; } bool Imprimir(const ContaBancaria &conta) { chamadasAImprimir++; return true; } int ChamadasAImprimir() const { return chamadasAImprimir; } private: int chamadasAImprimir; };
  • 33. 10/10  Nosso teste pode ficar assim: TEST( TesteContaBancaria, terminalConsegueImprimirExtrato ) { ContaBancaria conta; conta.Depositar( 1000 ); conta.Sacar( 500 ); ImpressoraExtrato *impressora = new ImpressoraExtratoFalsa(); TerminalBancario terminal; bool imprimiu = terminal.Imprimir(conta, *impressora ); YAFFUT_EQUAL( 1, impressora->ChamadasAImprimir() ); YAFFUT_CHECK( imprimiu ); delete impressora; }
  • 34. Ter que criar manualmente implementações falsas (classes falsas) e contabilizar a execução de cada método é trabalhoso.  Porém, há frameworks de teste que permitem a criação automática de implementações falsas (chamadas de Mocks), bastando apenas definir o comportamento esperado dos métodos.  A contabilização da chamada também é feita automaticamente.
  • 35. Em C++ há bons frameworks de teste automatizado, porém, poucos com recursos de criação automática de mocks:  Isolator++  AMOP  MockitoPP  HippoMocks  etc.  Adotaremos o HippoMocks com Yaffut1. 1. Veja análise em http://devhints.blogspot.com/2010/11/bons-frameworks-c-para-criacao.html
  • 36. Feito usando Yaffut (já vem com ele).  É opensource.  É simples.  É poderoso.  É portátil.  http://www.assembla.com/spaces/hippomocks
  • 37. Sua classe principal é MockRepository, que permite criar um repositório de objetos falsos (mocks).  Permite criação de mocks através do método InterfaceMock.  Permite definir expectativas através do método ExpectCall.
  • 38. TEST( TesteContaBancaria, terminalConsegueImprimirExtrato ) { ContaBancaria conta; conta.Depositar( 1000 ); conta.Sacar( 500 ); MockRepository mr; // Repositório de mocks ImpressoraExtrato *impressora = mr.InterfaceMock< ImpressoraExtrato >(); // Cria um mock // Cria a expectativa mr.ExpectCall( impressora, ImpressoraExtrato::Imprimir ) .With( conta ) .Return( true ); TerminalBancario terminal; bool imprimiu = terminal.Imprimir(conta, *impressora ); YAFFUT_CHECK( imprimiu ); delete impressora; // Não precisa verificar NADA. // O framework verifica se a expectativa criada foi atendida! }
  • 39. TEST( TesteBomba, atirarNumaBombaFazExplodiLa ) { MockRepository mr; // Repositório de objetos falsos // Bomba falsa Bomba *bomba = mr.InterfaceMock< Bomba >(); // Expectativa do que deve acontecer com a bomba // ao ser acertada por um tiro mr.ExpectCall( bomba, Bomba::Explodir ); Jogador jogador; Revolver revolver( 38 ); jogador.SegurarObjeto( revolver ); revolver.AtirarNoObjeto( bomba ); // Deve fazê-la explodir }
  • 40. TDD em C++ Thiago Delgado Pinto