Apresentação do Nuno Caneco sobre Utilização de Mock Objects em Testes Unitários na 29a Reunião Presencial da Comunidade NetPonto em Lisboa (http://netponto.org).
4. Nuno Caneco
Consultor Sénior na |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 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
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]
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);
}
}
9. 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
10. 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”
11. 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”
12. Motivação
Sistema
Serviços
Business
DAL/RAL
Sistemas externos
BD
13. 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
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 tal um exemplo?
CustomerManager
ICustomerReader IInvoiceReader
CustomerReader InvoiceReader
16. E que tal um exemplo?
CustomerManager
ICustomerReader IInvoiceReader
CustomerReader InvoiceReader
17. E que tal um exemplo?
CustomerManager
ICustomerReader IInvoiceReader
CustomerReader InvoiceReader
18. E que tal um exemplo?
CustomerManager
ICustomerReader IInvoiceReader
CustomerReader InvoiceReader
19. E que tal um exemplo?
CustomerManagerTest CustomerManager
ICustomerReader IInvoiceReader
CustomerReader InvoiceReader
20. E que tal um exemplo?
CustomerManagerTest CustomerManager
ICustomerReader IInvoiceReader
CustomerReaderMock CustomerReader InvoiceReader invoiceReaderMock
21. E que tal um exemplo?
CustomerManagerTest CustomerManager
ICustomerReader IInvoiceReader
CustomerReaderMock CustomerReader InvoiceReader invoiceReaderMock
22. E que tal um exemplo?
CustomerManagerTest CustomerManager
ICustomerReader IInvoiceReader
CustomerReaderMock CustomerReader InvoiceReader invoiceReaderMock
23. 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
24. 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
25. Aplicabilidade
• A todo o código C# que seja testável
–Serviços WCF
–Aplicações MVC
–Aplicações WPF
–…
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çã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
33. 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
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
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! :)
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?
Passamos a vida a testar as nossas aplicaçõesTestes dependem deDimensão da aplicaçãoCriticidade para o negócioExposição da aplicação…
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
Com certeza estão familiarizados, mas para dar enquadramento:
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
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
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
O objectivo dos mocks é substituir dependências por objectos simulados que imitam uma dependência real
Preparar para demo
REFERIR QUE DEMO ESTÁ NO GITHUB
O teste unitário de cada classe utilizar mocks das dependências directas dessa classe.Abordagem mais purista
Mockar as fronteiras do sistema permite maximizar a coverageImplementar testes nas camadas superiores da aplicaçãoImplementar menor número de testes
Estas dicas são discutíveisResultam da minha experiência pessoalNão são verdade absoluta