29ª Reunião Lisboa - 26/05/2012   http://netponto.org




   Utilização de Mock Objects em Testes Unitários
                                      Nuno Caneco
Patrocinador “GOLD”
Patrocinadores “Silver”
Nuno Caneco
Consultor Sénior na |create|it|

Áreas de interesse:
• SOA e Integração
• WCF
• desenvolvimento core
• Dependency Injection.
Agenda
•   Unit tests
•   Mocking frameworks
•   Demo
•   Considerações de arquitectura
•   Dicas
Testes e mais testes…
Testes de performance     Testes de sistema

   Testes de carga      Testes de usabilidade

 Testes de aceitação      Testes funcionais

   Testes unitários     Testes de segurança

 Testes de integração
Testes unitários
• Objectivo:
  – Testar a lógica de um método de forma isolada, tendo
    em conta os vários inputs possíveis e tendo em
    atenção casos de fronteira e valores inválidos.

• Características:
  – Repetíveis
  – Idempotentes
  – Não depender de outros testes
  – Inócuos
Exemplo
 [TestClass]
 public class SaleRecordsReaderTest
 {
     private SaleRecordsReader GetReader()
     {
         return new SaleRecordsReader();
     }

     [TestMethod]
     public void ListSaleRecordTest()
     {
         var reader = GetReader();

         var saleRecords = reader.ListSaleRecords();

         Assert.IsNotNull(saleRecords);
         Assert.IsTrue(saleRecords.Count > 0);
     }
 }
Alguns impedimentos e dificuldades
• UI: É difícil de testar código de interface
   – HTML/Javascript
• Acessibilidade
   – dos métodos: private, protected
   – da classe: internal
• Dependências
   – Persistência: BD, Lista de SharePoint
   – Sistemas externos
   – Utilização de providers: Membership providers, …
• Classes binded a determinados contextos
   – Ex.: CodeBehind de páginas .ASPX
Mitos
• “O meu código é perfeito!! Não é preciso testar.”

• “Não vale a pena fazer testes unitários. Basta clicar naquele link e
  pronto… Está testado!”

• “O projecto precisa de tempo para fazer testes unitários”

• “Eh pá… tenho que ter uma BD com dados de teste…”

• “Tenho muitas dependências. Não é possível abstrair-me dos
  sistemas externos”
Mitos
• “O meu código é perfeito!! Não é preciso testar.”

• “Não vale a pena fazer testes unitários. Basta clicar naquele link e
  pronto… Está testado!”

• “O projecto precisa de tempo para fazer testes unitários”

• “Eh pá… tenho que ter uma BD com dados de teste…”

• “Tenho muitas dependências. Não é possível abstrair-me dos
  sistemas externos”
Motivação
   Sistema
                                      Serviços



                                      Business



                                      DAL/RAL




                  Sistemas externos
             BD
Mocks com unit tests
In object-oriented programming, mock objects are
simulated objects that mimic the behavior of real
objects in controlled ways.

A computer programmer typically creates a mock object to test the
behavior of some other object, in much the same way that a car
designer uses a crash test dummy to simulate the dynamic behavior of
a human in vehicle impacts.



                        http://en.wikipedia.org/wiki/Mock_object
Estratégia de implementação
1.     Gerar mock
     – Usar framework de mocking para gerar mocks das dependências da classe a
       testar

2.     Substituir dependência pelo mock
     – Inicializar classe a ser testada com o mock em substituição da implementação
       “real”

3.     Programa o comportamento do mock
     – Programar os mocks para retornar determinados outputs em função dos inputs
         • Valores de retorno
         • Excepções

4.     Aferir o comportamento da classe em teste
E que tal um exemplo?
                   CustomerManager




       ICustomerReader           IInvoiceReader



       CustomerReader            InvoiceReader
E que tal um exemplo?
                   CustomerManager




       ICustomerReader           IInvoiceReader



       CustomerReader            InvoiceReader
E que tal um exemplo?
                   CustomerManager




       ICustomerReader           IInvoiceReader



       CustomerReader            InvoiceReader
E que tal um exemplo?
                   CustomerManager




       ICustomerReader           IInvoiceReader



       CustomerReader            InvoiceReader
E que tal um exemplo?
 CustomerManagerTest               CustomerManager




                       ICustomerReader           IInvoiceReader



                       CustomerReader            InvoiceReader
E que tal um exemplo?
    CustomerManagerTest               CustomerManager




                          ICustomerReader           IInvoiceReader


CustomerReaderMock        CustomerReader            InvoiceReader    invoiceReaderMock
E que tal um exemplo?
    CustomerManagerTest               CustomerManager




                          ICustomerReader           IInvoiceReader


CustomerReaderMock        CustomerReader            InvoiceReader    invoiceReaderMock
E que tal um exemplo?
    CustomerManagerTest               CustomerManager




                          ICustomerReader           IInvoiceReader


CustomerReaderMock        CustomerReader            InvoiceReader    invoiceReaderMock
E que tal um exemplo?
    CustomerManagerTest               CustomerManager




                          ICustomerReader           IInvoiceReader


CustomerReaderMock        CustomerReader            InvoiceReader       invoiceReaderMock




Os mocks substituem as classes reais no contexto de um teste unitário
O objectivo
• Evitar dependências
  – Dados (base-de-dados, configuração, …)
  – Estado de sistemas externos (CRM, ERP, …)
  – Contas de utilizador
  – Setup de ambientes com dados de teste

• Testar vários cenários de negócio e condições de
  fronteira
  – Nulos, valores inválidos, decisões em função de valores
    específicos
Aplicabilidade
• A todo o código C# que seja testável
  –Serviços WCF
  –Aplicações MVC
  –Aplicações WPF
  –…
Frameworks de mocking
•   Microsoft Moles (Fakes no VS11)
•   NMock
•   EasyMock.NET
•   TypeMock Isolator (Commercial / Paid)
•   Rhino Mocks
•   Moq
•   NSubstitute
•   JustMock (Commercial / Paid)
•   FakeItEasy
Caso de uso
https://github.com/nmcc/unit-test-mock-demo
Questões?
Considerações de arquitectura
• É necessário fazer override do método .Equals() para os
  objectos de input dos métodos

• Construtor que receba as interfaces das dependências

• Todas as dependências devem ser declaradas como
  interfaces
   – Usar “Ctrl+R, I” para gerar interfaces automaticamente

• É conveniente que os testes herdem de uma classe base
  que contém os mocks
Dependency Injection
• Substituição das dependências é
  automática

• Evita múltiplos construtores das classes a
  testar

• Código de inicialização do container fica na
  classe base de testes
Técnica:
Mocks de dependências directas
    CustomerManagerTest               CustomerManager




                          ICustomerReader           IInvoiceReader


CustomerReaderMock        CustomerReader            InvoiceReader    InvoiceReaderMock
Técnica:
Mock das fronteiras
    Sistema
                                          Serviços



                                          Business



                                          DAL/RAL




                      Sistemas externos
              BD
Dicas
• Classe de teste junto à classe testada
   – Ajuda a lembrar que existem testes
   – Utilizar #if para não compilar testes em Release

• Mock das fronteiras da aplicação
   – Permite atingir coverage elevada com menor número de testes

• Usar uma classe base para declarar os mocks

• Usar dependency injection
   – Permite injectar automaticamente os mocks numa classe base
   – Evitando a repetição da criação dos mocks pelas várias classes de teste
Prós e contras

  + confiança no código             Testes têm que ser mantidos
  + confiança em                    O código pode ter que ser
   refactorizações                    estruturado para ser testável
  Minimiza testes funcionais        Nem todo o código é testável
  Utilização de mocks
   “descomplica” testes unitários
  Execução automatizada com
   integração contínua
Referências
Rhino mocks
  – http://hibernatingrhinos.com/open-source/rhino-mocks


Demo
  – https://github.com/nmcc/unit-test-mock-demo
Patrocinador “GOLD”
Patrocinadores “Silver”
Questões?
Próximas reuniões presenciais
• 26-05-2012 – Maio
• 02-06-2012 – Junho (Coimbra)
• 16-06-2012 – Junho
• 21-07-2012 – Julho

Reserva estes dias na agenda! :)
Obrigado!
Nuno Caneco
Mail/MSN: nuno.caneco@create.pt
Blog: http://blogit.create.pt/blogs/nunocaneco/
Twitter: @NunoCaneco
Gamertag: nunocaneco

Utilização de Mock Objects em Testes Unitários

  • 1.
    29ª Reunião Lisboa- 26/05/2012 http://netponto.org Utilização de Mock Objects em Testes Unitários Nuno Caneco
  • 2.
  • 3.
  • 4.
    Nuno Caneco Consultor Séniorna |create|it| Áreas de interesse: • SOA e Integração • WCF • desenvolvimento core • Dependency Injection.
  • 5.
    Agenda • Unit tests • Mocking frameworks • Demo • Considerações de arquitectura • Dicas
  • 6.
    Testes e maistestes… Testes de performance Testes de sistema Testes de carga Testes de usabilidade Testes de aceitação Testes funcionais Testes unitários Testes de segurança Testes de integração
  • 7.
    Testes unitários • Objectivo: – Testar a lógica de um método de forma isolada, tendo em conta os vários inputs possíveis e tendo em atenção casos de fronteira e valores inválidos. • Características: – Repetíveis – Idempotentes – Não depender de outros testes – Inócuos
  • 8.
    Exemplo [TestClass] publicclass SaleRecordsReaderTest { private SaleRecordsReader GetReader() { return new SaleRecordsReader(); } [TestMethod] public void ListSaleRecordTest() { var reader = GetReader(); var saleRecords = reader.ListSaleRecords(); Assert.IsNotNull(saleRecords); Assert.IsTrue(saleRecords.Count > 0); } }
  • 9.
    Alguns impedimentos edificuldades • UI: É difícil de testar código de interface – HTML/Javascript • Acessibilidade – dos métodos: private, protected – da classe: internal • Dependências – Persistência: BD, Lista de SharePoint – Sistemas externos – Utilização de providers: Membership providers, … • Classes binded a determinados contextos – Ex.: CodeBehind de páginas .ASPX
  • 10.
    Mitos • “O meucódigo é perfeito!! Não é preciso testar.” • “Não vale a pena fazer testes unitários. Basta clicar naquele link e pronto… Está testado!” • “O projecto precisa de tempo para fazer testes unitários” • “Eh pá… tenho que ter uma BD com dados de teste…” • “Tenho muitas dependências. Não é possível abstrair-me dos sistemas externos”
  • 11.
    Mitos • “O meucódigo é perfeito!! Não é preciso testar.” • “Não vale a pena fazer testes unitários. Basta clicar naquele link e pronto… Está testado!” • “O projecto precisa de tempo para fazer testes unitários” • “Eh pá… tenho que ter uma BD com dados de teste…” • “Tenho muitas dependências. Não é possível abstrair-me dos sistemas externos”
  • 12.
    Motivação Sistema Serviços Business DAL/RAL Sistemas externos BD
  • 13.
    Mocks com unittests In object-oriented programming, mock objects are simulated objects that mimic the behavior of real objects in controlled ways. A computer programmer typically creates a mock object to test the behavior of some other object, in much the same way that a car designer uses a crash test dummy to simulate the dynamic behavior of a human in vehicle impacts. http://en.wikipedia.org/wiki/Mock_object
  • 14.
    Estratégia de implementação 1. Gerar mock – Usar framework de mocking para gerar mocks das dependências da classe a testar 2. Substituir dependência pelo mock – Inicializar classe a ser testada com o mock em substituição da implementação “real” 3. Programa o comportamento do mock – Programar os mocks para retornar determinados outputs em função dos inputs • Valores de retorno • Excepções 4. Aferir o comportamento da classe em teste
  • 15.
    E que talum exemplo? CustomerManager ICustomerReader IInvoiceReader CustomerReader InvoiceReader
  • 16.
    E que talum exemplo? CustomerManager ICustomerReader IInvoiceReader CustomerReader InvoiceReader
  • 17.
    E que talum exemplo? CustomerManager ICustomerReader IInvoiceReader CustomerReader InvoiceReader
  • 18.
    E que talum exemplo? CustomerManager ICustomerReader IInvoiceReader CustomerReader InvoiceReader
  • 19.
    E que talum exemplo? CustomerManagerTest CustomerManager ICustomerReader IInvoiceReader CustomerReader InvoiceReader
  • 20.
    E que talum exemplo? CustomerManagerTest CustomerManager ICustomerReader IInvoiceReader CustomerReaderMock CustomerReader InvoiceReader invoiceReaderMock
  • 21.
    E que talum exemplo? CustomerManagerTest CustomerManager ICustomerReader IInvoiceReader CustomerReaderMock CustomerReader InvoiceReader invoiceReaderMock
  • 22.
    E que talum exemplo? CustomerManagerTest CustomerManager ICustomerReader IInvoiceReader CustomerReaderMock CustomerReader InvoiceReader invoiceReaderMock
  • 23.
    E que talum exemplo? CustomerManagerTest CustomerManager ICustomerReader IInvoiceReader CustomerReaderMock CustomerReader InvoiceReader invoiceReaderMock Os mocks substituem as classes reais no contexto de um teste unitário
  • 24.
    O objectivo • Evitardependências – Dados (base-de-dados, configuração, …) – Estado de sistemas externos (CRM, ERP, …) – Contas de utilizador – Setup de ambientes com dados de teste • Testar vários cenários de negócio e condições de fronteira – Nulos, valores inválidos, decisões em função de valores específicos
  • 25.
    Aplicabilidade • A todoo código C# que seja testável –Serviços WCF –Aplicações MVC –Aplicações WPF –…
  • 26.
    Frameworks de mocking • Microsoft Moles (Fakes no VS11) • NMock • EasyMock.NET • TypeMock Isolator (Commercial / Paid) • Rhino Mocks • Moq • NSubstitute • JustMock (Commercial / Paid) • FakeItEasy
  • 27.
  • 28.
  • 29.
    Considerações de arquitectura •É necessário fazer override do método .Equals() para os objectos de input dos métodos • Construtor que receba as interfaces das dependências • Todas as dependências devem ser declaradas como interfaces – Usar “Ctrl+R, I” para gerar interfaces automaticamente • É conveniente que os testes herdem de uma classe base que contém os mocks
  • 30.
    Dependency Injection • Substituiçãodas dependências é automática • Evita múltiplos construtores das classes a testar • Código de inicialização do container fica na classe base de testes
  • 31.
    Técnica: Mocks de dependênciasdirectas CustomerManagerTest CustomerManager ICustomerReader IInvoiceReader CustomerReaderMock CustomerReader InvoiceReader InvoiceReaderMock
  • 32.
    Técnica: Mock das fronteiras Sistema Serviços Business DAL/RAL Sistemas externos BD
  • 33.
    Dicas • Classe deteste junto à classe testada – Ajuda a lembrar que existem testes – Utilizar #if para não compilar testes em Release • Mock das fronteiras da aplicação – Permite atingir coverage elevada com menor número de testes • Usar uma classe base para declarar os mocks • Usar dependency injection – Permite injectar automaticamente os mocks numa classe base – Evitando a repetição da criação dos mocks pelas várias classes de teste
  • 34.
    Prós e contras  + confiança no código  Testes têm que ser mantidos  + confiança em  O código pode ter que ser refactorizações estruturado para ser testável  Minimiza testes funcionais  Nem todo o código é testável  Utilização de mocks “descomplica” testes unitários  Execução automatizada com integração contínua
  • 35.
    Referências Rhino mocks – http://hibernatingrhinos.com/open-source/rhino-mocks Demo – https://github.com/nmcc/unit-test-mock-demo
  • 36.
  • 37.
  • 38.
  • 39.
    Próximas reuniões presenciais •26-05-2012 – Maio • 02-06-2012 – Junho (Coimbra) • 16-06-2012 – Junho • 21-07-2012 – Julho Reserva estes dias na agenda! :)
  • 40.
    Obrigado! Nuno Caneco Mail/MSN: nuno.caneco@create.pt Blog:http://blogit.create.pt/blogs/nunocaneco/ Twitter: @NunoCaneco Gamertag: nunocaneco

Notas do Editor

  • #6 Questões à audiência:Quemjá usou testes unitários?Quem AINDA usa testes unitários?Os testes unitários do projecto estão a passar?Quem usa técnicas de mocking?
  • #7 Passamos a vida a testar as nossas aplicaçõesTestes dependem deDimensão da aplicaçãoCriticidade para o negócioExposição da aplicação…
  • #8 Testes unitários:“quando entra o porco, sai a salsicha”Testes unitários: isolados, completos e condições de fronteiraTestes unitários vs testes de integração vsframework de testes unitários
  • #9 Com certeza estão familiarizados, mas para dar enquadramento:
  • #11 Levantar discussão sobre os mitos “Os mocks vêm ajudar”“pelo menos nos que não envolvem o ego dos programadores )PERGUNTA À AUDIÊNCIA: Revêem-se nestas afirmações?Preparar para motivação dos mocks
  • #12 Levantar discussão sobre os mitos “Os mocks vêm ajudar”“pelo menos nos que não envolvem o ego dos programadores )PERGUNTA À AUDIÊNCIA: Revêem-se nestas afirmações?Preparar para motivação dos mocks
  • #13 Passando a falar em mocksEstamos a construir um sistemaP.ex. 3 camadasQue necessita de componentes externasConstruimos classesE relações entre elasQueremos testar uma classeTestes unitários: testar a classe de forma isolada
  • #14 O objectivo dos mocks é substituir dependências por objectos simulados que imitam uma dependência real
  • #29 Preparar para demo
  • #30 REFERIR QUE DEMO ESTÁ NO GITHUB
  • #34 O teste unitário de cada classe utilizar mocks das dependências directas dessa classe.Abordagem mais purista
  • #35 Mockar as fronteiras do sistema permite maximizar a coverageImplementar testes nas camadas superiores da aplicaçãoImplementar menor número de testes
  • #36 Estas dicas são discutíveisResultam da minha experiência pessoalNão são verdade absoluta