Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
Injeção de Dependência e    Testes com Dublês                  2º Locaweb Tec Day                            04.02.2009
Conteúdo• Exemplo• Injeção de Dependência (DI)• Testes com Dublês (Doubles)
Exemplopublic List<Phone> phonesForCompany(String name) {    List<Phone> phones = finder.findAll();    Iterator<Phone> it ...
Continuando o Exemplo• Criando interface   – public interface PhoneFinder {         List<Phone> findAll();     }• Criação ...
Dependência• PhoneLister depende da interface e da implementação• Como depender somente da interface?                     ...
Idéia Básica - Injeção                         Injeção                                   Framework                        ...
Tipos de Injeção• Injeção Por Construtor   public PhoneLister(PhoneFinder finder) {     this.finder = finder;   }• Por Set...
XML<objects>  <object id=“myFinder”          class="br.com.locaweb.pabx.MySqlPhoneFinder">  </object>  <object id=“phoneLi...
Usando na aplicaçãopublic void test() { Repository repository = new Repository("objects.xml"); PhoneLister lister = reposi...
Fábrica de Objetos• Singleton   – Instância única compartilhada do objeto   – Uso padrão, mais comum   – Objetos de serviç...
Fábrica de Objetos                     10
Fábrica de Objetos                     Repositório                        S          P      Cliente 1                     ...
Fábrica de Objetos                     Repositório                        S          P      Cliente 1                     ...
Fábrica de Objetos                       Repositório                          S          P      Cliente 1                 ...
Fábrica de Objetos                       Repositório                          S          P      Cliente 1                 ...
Fábrica de Objetos                            Repositório                               S          P      Cliente 1       ...
Fábrica de Objetos                            Repositório                               S          P      Cliente 1       ...
Fábrica de Objetos                            Repositório                               S          P      Cliente 1       ...
Vantagens de usar Injeção de Dependência                                           11
Vantagens de usar Injeção de Dependência• Ajuda a escrever código que é fácil de testar: é só criar  objetos e atribuir as...
Vantagens de usar Injeção de Dependência• Ajuda a escrever código que é fácil de testar: é só criar  objetos e atribuir as...
Vantagens de usar Injeção de Dependência• Ajuda a escrever código que é fácil de testar: é só criar  objetos e atribuir as...
Vantagens de usar Injeção de Dependência• Ajuda a escrever código que é fácil de testar: é só criar  objetos e atribuir as...
Vantagens de usar Injeção de Dependência• Ajuda a escrever código que é fácil de testar: é só criar  objetos e atribuir as...
Frameworks para todas as linguagens                                      12
Frameworks para todas as linguagens• Java - Spring, PicoContainer, HiveMind                                           12
Frameworks para todas as linguagens• Java - Spring, PicoContainer, HiveMind• PHP - DIContainer                            ...
Frameworks para todas as linguagens• Java - Spring, PicoContainer, HiveMind• PHP - DIContainer• .NET - Spring.NET, PicoCon...
Frameworks para todas as linguagens•   Java - Spring, PicoContainer, HiveMind•   PHP - DIContainer•   .NET - Spring.NET, P...
Frameworks para todas as linguagens•   Java - Spring, PicoContainer, HiveMind•   PHP - DIContainer•   .NET - Spring.NET, P...
Frameworks para todas as linguagens•   Java - Spring, PicoContainer, HiveMind•   PHP - DIContainer•   .NET - Spring.NET, P...
Frameworks para todas as linguagens•   Java - Spring, PicoContainer, HiveMind•   PHP - DIContainer•   .NET - Spring.NET, P...
Frameworks para todas as linguagens•   Java - Spring, PicoContainer, HiveMind•   PHP - DIContainer•   .NET - Spring.NET, P...
Frameworks para todas as linguagens•   Java - Spring, PicoContainer, HiveMind•   PHP - DIContainer•   .NET - Spring.NET, P...
DI – Linha do Tempo
Construtor ou Setter?
Construtor ou Setter?• Construtor com parâmetros deixa claro o que é preciso  para criar o objeto
Construtor ou Setter?• Construtor com parâmetros deixa claro o que é preciso  para criar o objeto• Usando construtor evita...
Construtor ou Setter?• Construtor com parâmetros deixa claro o que é preciso  para criar o objeto• Usando construtor evita...
Construtor ou Setter?• Construtor com parâmetros deixa claro o que é preciso  para criar o objeto• Usando construtor evita...
Construtor ou Setter?• Construtor com parâmetros deixa claro o que é preciso  para criar o objeto• Usando construtor evita...
Voltando ao nosso PhoneListerpublic List<Phone> phonesForCompany(String name) {    List<Phone> phones = finder.findAll(); ...
Voltando ao nosso PhoneListerpublic List<Phone> phonesForCompany(String name) {                       Finder    List<Phone...
Voltando ao nosso PhoneListerpublic List<Phone> phonesForCompany(String name) {                       Finder    List<Phone...
Voltando ao nosso PhoneListerpublic List<Phone> phonesForCompany(String name) {                       Finder    List<Phone...
Voltando ao nosso PhoneListerpublic List<Phone> phonesForCompany(String name) {                       Finder    List<Phone...
Voltando ao nosso PhoneListerpublic List<Phone> phonesForCompany(String name) {                       Finder    List<Phone...
Voltando ao nosso PhoneListerpublic List<Phone> phonesForCompany(String name) {                       Finder    List<Phone...
Testes com Dublês (Doubles)                  Double                              16
Testes com Dublês (Doubles)                  Double                              16
Testes com Dublês (Doubles)                   DoubleDummyObject                               16
Testes com Dublês (Doubles)                   DoubleDummy          StubObject                               16
Testes com Dublês (Doubles)                   DoubleDummy          Stub      SpyObject                               16
Testes com Dublês (Doubles)                   DoubleDummy          Stub      Spy        MockObject                        ...
Testes com Dublês (Doubles)                   DoubleDummy          Stub      Spy        Mock   FakeObject                 ...
Dummy Object•   Objetos que nunca são usados, só servem para preencher parâmetros                                         ...
Dummy Object•    Objetos que nunca são usados, só servem para preencher parâmetros    public void testInvoice_addLineItem_...
Dummy Object•    Objetos que nunca são usados, só servem para preencher parâmetros    public void testInvoice_addLineItem_...
Dummy Object•    Objetos que nunca são usados, só servem para preencher parâmetros    public void testInvoice_addLineItem_...
Dummy Object•    Objetos que nunca são usados, só servem para preencher parâmetros    public void testInvoice_addLineItem_...
Dummy Object•    Objetos que nunca são usados, só servem para preencher parâmetros    public void testInvoice_addLineItem_...
Dummy Object•    Objetos que nunca são usados, só servem para preencher parâmetros    public void testInvoice_addLineItem_...
Stub•   Provê alguns dados estáticos que serão usados nos testes•   Não funciona para outras coisas além do que está no te...
Stub•   Provê alguns dados estáticos que serão usados nos testes•   Não funciona para outras coisas além do que está no te...
Spy•   Muito parecido com Stub, mas com a diferença de que “grava” algumas coisas                                         ...
Spy•   Muito parecido com Stub, mas com a diferença de que “grava” algumas coisasclass OrderStateTester {    public void t...
Spy•   Muito parecido com Stub, mas com a diferença de que “grava” algumas coisasclass OrderStateTester {    public void t...
O que são Mock Objects?   Years later, Mock objects are still quite controversial, often           misused and sometimes m...
O que são Mock Objects?• Cada pessoa entende de um jeito diferente• Terminologia ambígua• Ficou famoso inicialmente na com...
Código Mockpublic class FTPUploaderTest {    public void shouldUploadOnePhoneConfig() throws Exception {        FTPUtils f...
Código Mockpublic class FTPUploaderTest {    public void shouldUploadOnePhoneConfig() throws Exception {        FTPUtils f...
Código Mockpublic class FTPUploaderTest {    public void shouldUploadOnePhoneConfig() throws Exception {        FTPUtils f...
Código Mockpublic class FTPUploaderTest {    public void shouldUploadOnePhoneConfig() throws Exception {        FTPUtils f...
Código Mockpublic class FTPUploaderTest {    public void shouldUploadOnePhoneConfig() throws Exception {        FTPUtils f...
Código Mockpublic class FTPUploaderTest {    public void shouldUploadOnePhoneConfig() throws Exception {        FTPUtils f...
Fake Object•   Têm uma implementação completa, mas simples•   Não vai para produção•   Exemplo: banco de dados em memória ...
Fake Object    •   Têm uma implementação completa, mas simples    •   Não vai para produção    •   Exemplo: banco de dados...
Fake Object    •   Têm uma implementação completa, mas simples    •   Não vai para produção    •   Exemplo: banco de dados...
Implementação de Fake Objectpublic class InMemoryDatabase implements FlightDao{  private List airports = new Vector();    ...
Mocks nas Linguagens
Mocks nas Linguagens• Java - EasyMock, JMock, Mockito
Mocks nas Linguagens• Java - EasyMock, JMock, Mockito• Ruby - Mocha, RSpec?
Mocks nas Linguagens• Java - EasyMock, JMock, Mockito• Ruby - Mocha, RSpec?• .NET - NMock, Rhino Mocks
Mocks nas Linguagens•   Java - EasyMock, JMock, Mockito•   Ruby - Mocha, RSpec?•   .NET - NMock, Rhino Mocks•   Perl - Tes...
Mocks nas Linguagens•   Java - EasyMock, JMock, Mockito•   Ruby - Mocha, RSpec?•   .NET - NMock, Rhino Mocks•   Perl - Tes...
Mocks nas Linguagens•   Java - EasyMock, JMock, Mockito•   Ruby - Mocha, RSpec?•   .NET - NMock, Rhino Mocks•   Perl - Tes...
Testes com Doubles - Recapitulando                   DoubleDummy          Stub      Spy      Mock     FakeObject          ...
Testes com Doubles - Recapitulando                    DoubleDummy             Stub    Spy      Mock     FakeObject Preench...
Testes com Doubles - Recapitulando                          DoubleDummy               Stub        Spy     Mock   FakeObjec...
Testes com Doubles - Recapitulando                          DoubleDummy               Stub        Spy      Mock   FakeObje...
Testes com Doubles - Recapitulando                          DoubleDummy               Stub        Spy       Mock        Fa...
Testes com Doubles - Recapitulando                          DoubleDummy               Stub        Spy       Mock         F...
QuizDublês + Injeção de Dependência =
QuizDublês + Injeção de Dependência = Testes
Referências•   http://www.springframework.org/documentation•   http://martinfowler.com/articles/injection.html•   http://m...
Para aqueles que buscam sucesso em projetos e negócios, LOCAWEB oferece soluções        inovadoras em Hosted IT Services d...
Upcoming SlideShare
Loading in …5
×

Injeção de Dependência e Testes com Dublês

3,393 views

Published on

Injeção de Dependência e Testes com Dublês

  1. 1. Injeção de Dependência e Testes com Dublês 2º Locaweb Tec Day 04.02.2009
  2. 2. Conteúdo• Exemplo• Injeção de Dependência (DI)• Testes com Dublês (Doubles)
  3. 3. Exemplopublic List<Phone> phonesForCompany(String name) { List<Phone> phones = finder.findAll(); Iterator<Phone> it = phones.iterator(); for (Phone phone: phones) { Phone phone = it.next(); if (!phone.getCompany().equals(name)) { phones.remove(phone); } } return phones;} 3
  4. 4. Continuando o Exemplo• Criando interface – public interface PhoneFinder { List<Phone> findAll(); }• Criação de instância continua obrigatória – public class PhoneLister { private PhoneFinder finder; public PhoneLister() { finder = new MySqlPhoneFinder(); } } 4
  5. 5. Dependência• PhoneLister depende da interface e da implementação• Como depender somente da interface? 5
  6. 6. Idéia Básica - Injeção Injeção Framework Injeção de Dependência 6
  7. 7. Tipos de Injeção• Injeção Por Construtor public PhoneLister(PhoneFinder finder) { this.finder = finder; }• Por Setter class PhoneLister { public PhoneLister(){…} public void setPhoneFinder(PhoneFinder finder) { this.finder = finder; } } 7
  8. 8. XML<objects> <object id=“myFinder” class="br.com.locaweb.pabx.MySqlPhoneFinder"> </object> <object id=“phoneLister” class="br.com.locaweb.pabx.PhoneLister"> <property name=“phoneFinder" ref=“myFinder"/> </object></objects> 8
  9. 9. Usando na aplicaçãopublic void test() { Repository repository = new Repository("objects.xml"); PhoneLister lister = repository.object(“phoneLister"); List phones = lister.phonesForCompany("LW Telecom"); assertEquals(“1135443500",phones.get(0).getNumber());} 9
  10. 10. Fábrica de Objetos• Singleton – Instância única compartilhada do objeto – Uso padrão, mais comum – Objetos de serviço sem estado (stateless)• Protótipos – Cada chamada cria um novo objeto• Escopos de Objetos Customizados – Objetos armazenados fora do controle do container (ex: request, session em uma aplicação Web) 10
  11. 11. Fábrica de Objetos 10
  12. 12. Fábrica de Objetos Repositório S P Cliente 1 Cliente 2 10
  13. 13. Fábrica de Objetos Repositório S P Cliente 1 Cliente 2 S1 10
  14. 14. Fábrica de Objetos Repositório S P Cliente 1 Cliente 2 S1 S1 10
  15. 15. Fábrica de Objetos Repositório S P Cliente 1 Cliente 2 S1 S1 S1 10
  16. 16. Fábrica de Objetos Repositório S P Cliente 1 Cliente 2 S1 S1 P1 S1 10
  17. 17. Fábrica de Objetos Repositório S P Cliente 1 Cliente 2 S1 S1 P1 S1 P2 10
  18. 18. Fábrica de Objetos Repositório S P Cliente 1 Cliente 2 S1 S1 P1 S1 P2 P3 10
  19. 19. Vantagens de usar Injeção de Dependência 11
  20. 20. Vantagens de usar Injeção de Dependência• Ajuda a escrever código que é fácil de testar: é só criar objetos e atribuir as propriedades desejadas usando os setters 11
  21. 21. Vantagens de usar Injeção de Dependência• Ajuda a escrever código que é fácil de testar: é só criar objetos e atribuir as propriedades desejadas usando os setters• Facilita boas práticas de programação: uso de interfaces no lugar de classes 11
  22. 22. Vantagens de usar Injeção de Dependência• Ajuda a escrever código que é fácil de testar: é só criar objetos e atribuir as propriedades desejadas usando os setters• Facilita boas práticas de programação: uso de interfaces no lugar de classes• Não envasivo: o código do sistema depende o mínimo possível da API do Framework 11
  23. 23. Vantagens de usar Injeção de Dependência• Ajuda a escrever código que é fácil de testar: é só criar objetos e atribuir as propriedades desejadas usando os setters• Facilita boas práticas de programação: uso de interfaces no lugar de classes• Não envasivo: o código do sistema depende o mínimo possível da API do Framework• Dependências são explícitas e evidentes 11
  24. 24. Vantagens de usar Injeção de Dependência• Ajuda a escrever código que é fácil de testar: é só criar objetos e atribuir as propriedades desejadas usando os setters• Facilita boas práticas de programação: uso de interfaces no lugar de classes• Não envasivo: o código do sistema depende o mínimo possível da API do Framework• Dependências são explícitas e evidentes• Como os componentes não precisam procurar colaboradores em tempo de execução, o código fica mais fácil de escrever e manter 11
  25. 25. Frameworks para todas as linguagens 12
  26. 26. Frameworks para todas as linguagens• Java - Spring, PicoContainer, HiveMind 12
  27. 27. Frameworks para todas as linguagens• Java - Spring, PicoContainer, HiveMind• PHP - DIContainer 12
  28. 28. Frameworks para todas as linguagens• Java - Spring, PicoContainer, HiveMind• PHP - DIContainer• .NET - Spring.NET, PicoContainer.NET 12
  29. 29. Frameworks para todas as linguagens• Java - Spring, PicoContainer, HiveMind• PHP - DIContainer• .NET - Spring.NET, PicoContainer.NET• Python - PyContainer, Spring Python 12
  30. 30. Frameworks para todas as linguagens• Java - Spring, PicoContainer, HiveMind• PHP - DIContainer• .NET - Spring.NET, PicoContainer.NET• Python - PyContainer, Spring Python• Ruby - Needle 12
  31. 31. Frameworks para todas as linguagens• Java - Spring, PicoContainer, HiveMind• PHP - DIContainer• .NET - Spring.NET, PicoContainer.NET• Python - PyContainer, Spring Python• Ruby - Needle• Perl - IOC Module 12
  32. 32. Frameworks para todas as linguagens• Java - Spring, PicoContainer, HiveMind• PHP - DIContainer• .NET - Spring.NET, PicoContainer.NET• Python - PyContainer, Spring Python• Ruby - Needle• Perl - IOC Module• Flex - Flicc 12
  33. 33. Frameworks para todas as linguagens• Java - Spring, PicoContainer, HiveMind• PHP - DIContainer• .NET - Spring.NET, PicoContainer.NET• Python - PyContainer, Spring Python• Ruby - Needle• Perl - IOC Module• Flex - Flicc 12
  34. 34. Frameworks para todas as linguagens• Java - Spring, PicoContainer, HiveMind• PHP - DIContainer• .NET - Spring.NET, PicoContainer.NET• Python - PyContainer, Spring Python• Ruby - Needle• Perl - IOC Module• Flex - Flicc• mais em http://en.wikipedia.org/wiki/Dependency_injection 12
  35. 35. DI – Linha do Tempo
  36. 36. Construtor ou Setter?
  37. 37. Construtor ou Setter?• Construtor com parâmetros deixa claro o que é preciso para criar o objeto
  38. 38. Construtor ou Setter?• Construtor com parâmetros deixa claro o que é preciso para criar o objeto• Usando construtor evita campos imutáveis de serem alterados
  39. 39. Construtor ou Setter?• Construtor com parâmetros deixa claro o que é preciso para criar o objeto• Usando construtor evita campos imutáveis de serem alterados• Cuidado: construtores com muitos parâmetros podem ser um indicativo de objeto com responsabilidades demais
  40. 40. Construtor ou Setter?• Construtor com parâmetros deixa claro o que é preciso para criar o objeto• Usando construtor evita campos imutáveis de serem alterados• Cuidado: construtores com muitos parâmetros podem ser um indicativo de objeto com responsabilidades demais• Construtor é ruim se tiver parâmetros simples como Strings: com setter você cria um método que identifica o que a string significa
  41. 41. Construtor ou Setter?• Construtor com parâmetros deixa claro o que é preciso para criar o objeto• Usando construtor evita campos imutáveis de serem alterados• Cuidado: construtores com muitos parâmetros podem ser um indicativo de objeto com responsabilidades demais• Construtor é ruim se tiver parâmetros simples como Strings: com setter você cria um método que identifica o que a string significa• Receita geral: comece com construtor e mude para setter se a coisa ficar complicada demais
  42. 42. Voltando ao nosso PhoneListerpublic List<Phone> phonesForCompany(String name) { List<Phone> phones = finder.findAll(); Iterator<Phone> it = phones.iterator(); for (Phone phone: phones) { Phone phone = it.next(); if (!phone.getCompany().equals(name)) { phones.remove(phone); } } return phones;} 15
  43. 43. Voltando ao nosso PhoneListerpublic List<Phone> phonesForCompany(String name) { Finder List<Phone> phones = finder.findAll(); Iterator<Phone> it = phones.iterator(); for (Phone phone: phones) { Phone phone = it.next(); if (!phone.getCompany().equals(name)) { phones.remove(phone); } } return phones;} 15
  44. 44. Voltando ao nosso PhoneListerpublic List<Phone> phonesForCompany(String name) { Finder List<Phone> phones = finder.findAll(); Iterator<Phone> it = phones.iterator(); for (Phone phone: phones) { Preencher os dados Phone phone = it.next(); no DB manualmente if (!phone.getCompany().equals(name)) { phones.remove(phone); } } return phones;} 15
  45. 45. Voltando ao nosso PhoneListerpublic List<Phone> phonesForCompany(String name) { Finder List<Phone> phones = finder.findAll(); Iterator<Phone> it = phones.iterator(); E se eu não tiver acesso ao banco? for (Phone phone: phones) { Preencher os dados Phone phone = it.next(); no DB manualmente if (!phone.getCompany().equals(name)) { phones.remove(phone); } } return phones;} 15
  46. 46. Voltando ao nosso PhoneListerpublic List<Phone> phonesForCompany(String name) { Finder List<Phone> phones = finder.findAll(); Iterator<Phone> it = phones.iterator(); E se eu não tiver acesso ao banco? for (Phone phone: phones) { Preencher os dados Phone phone = it.next(); no DB manualmente E se ele for lento demais? if (!phone.getCompany().equals(name)) { phones.remove(phone); } } return phones;} 15
  47. 47. Voltando ao nosso PhoneListerpublic List<Phone> phonesForCompany(String name) { Finder List<Phone> phones = finder.findAll(); Iterator<Phone> it = phones.iterator(); E se eu não tiver acesso ao banco? for (Phone phone: phones) { Preencher os dados Phone phone = it.next(); no DB manualmente E se ele for lento demais? if (!phone.getCompany().equals(name)) { E se o custo for phones.remove(phone); alto? } } return phones;} 15
  48. 48. Voltando ao nosso PhoneListerpublic List<Phone> phonesForCompany(String name) { Finder List<Phone> phones = finder.findAll(); Iterator<Phone> it = phones.iterator(); E se eu não tiver acesso ao banco? for (Phone phone: phones) { Preencher os dados Phone phone = it.next(); no DB manualmente E se ele for lento demais? if (!phone.getCompany().equals(name)) { E se o custo for phones.remove(phone); alto? } E se não tiver } banco ainda? return phones;} 15
  49. 49. Testes com Dublês (Doubles) Double 16
  50. 50. Testes com Dublês (Doubles) Double 16
  51. 51. Testes com Dublês (Doubles) DoubleDummyObject 16
  52. 52. Testes com Dublês (Doubles) DoubleDummy StubObject 16
  53. 53. Testes com Dublês (Doubles) DoubleDummy Stub SpyObject 16
  54. 54. Testes com Dublês (Doubles) DoubleDummy Stub Spy MockObject 16
  55. 55. Testes com Dublês (Doubles) DoubleDummy Stub Spy Mock FakeObject 16
  56. 56. Dummy Object• Objetos que nunca são usados, só servem para preencher parâmetros 17
  57. 57. Dummy Object• Objetos que nunca são usados, só servem para preencher parâmetros public void testInvoice_addLineItem_noECS() { final int QUANTITY = 1; Product product = new Product("Dummy Product"); State state = new State("West Dakota", "WD"); City city = new City("Centreville", state); Address address = new Address("123 Blake St.", city, "12345"); Customer customer= new Customer("Dummy Customer"); Invoice inv = new Invoice(customer); // Add an item to the invoice inv.addItemQuantity(product, QUANTITY); // Verify that item was inserted List lineItems = inv.getLineItems(); assertEquals("number of items", lineItems.size(), 1); LineItem actual = (LineItem)lineItems.get(0); LineItem expItem = new LineItem(inv, product, QUANTITY); assertLineItemsEqual("",expItem, actual); } 17
  58. 58. Dummy Object• Objetos que nunca são usados, só servem para preencher parâmetros public void testInvoice_addLineItem_noECS() { final int QUANTITY = 1; Dummy Product product = new Product("Dummy Product"); State state = new State("West Dakota", "WD"); City city = new City("Centreville", state); Address address = new Address("123 Blake St.", city, "12345"); Customer customer= new Customer("Dummy Customer"); Invoice inv = new Invoice(customer); // Add an item to the invoice inv.addItemQuantity(product, QUANTITY); // Verify that item was inserted List lineItems = inv.getLineItems(); assertEquals("number of items", lineItems.size(), 1); LineItem actual = (LineItem)lineItems.get(0); LineItem expItem = new LineItem(inv, product, QUANTITY); assertLineItemsEqual("",expItem, actual); } 17
  59. 59. Dummy Object• Objetos que nunca são usados, só servem para preencher parâmetros public void testInvoice_addLineItem_noECS() { final int QUANTITY = 1; Dummy Product product = new Product("Dummy Product"); Dummy State state = new State("West Dakota", "WD"); City city = new City("Centreville", state); Address address = new Address("123 Blake St.", city, "12345"); Customer customer= new Customer("Dummy Customer"); Invoice inv = new Invoice(customer); // Add an item to the invoice inv.addItemQuantity(product, QUANTITY); // Verify that item was inserted List lineItems = inv.getLineItems(); assertEquals("number of items", lineItems.size(), 1); LineItem actual = (LineItem)lineItems.get(0); LineItem expItem = new LineItem(inv, product, QUANTITY); assertLineItemsEqual("",expItem, actual); } 17
  60. 60. Dummy Object• Objetos que nunca são usados, só servem para preencher parâmetros public void testInvoice_addLineItem_noECS() { final int QUANTITY = 1; Dummy Product product = new Product("Dummy Product"); Dummy State state = new State("West Dakota", "WD"); Dummy City city = new City("Centreville", state); Address address = new Address("123 Blake St.", city, "12345"); Customer customer= new Customer("Dummy Customer"); Invoice inv = new Invoice(customer); // Add an item to the invoice inv.addItemQuantity(product, QUANTITY); // Verify that item was inserted List lineItems = inv.getLineItems(); assertEquals("number of items", lineItems.size(), 1); LineItem actual = (LineItem)lineItems.get(0); LineItem expItem = new LineItem(inv, product, QUANTITY); assertLineItemsEqual("",expItem, actual); } 17
  61. 61. Dummy Object• Objetos que nunca são usados, só servem para preencher parâmetros public void testInvoice_addLineItem_noECS() { final int QUANTITY = 1; Dummy Product product = new Product("Dummy Product"); Dummy State state = new State("West Dakota", "WD"); Dummy City city = new City("Centreville", state); Dummy Address address = new Address("123 Blake St.", city, "12345"); Customer customer= new Customer("Dummy Customer"); Invoice inv = new Invoice(customer); // Add an item to the invoice inv.addItemQuantity(product, QUANTITY); // Verify that item was inserted List lineItems = inv.getLineItems(); assertEquals("number of items", lineItems.size(), 1); LineItem actual = (LineItem)lineItems.get(0); LineItem expItem = new LineItem(inv, product, QUANTITY); assertLineItemsEqual("",expItem, actual); } 17
  62. 62. Dummy Object• Objetos que nunca são usados, só servem para preencher parâmetros public void testInvoice_addLineItem_noECS() { final int QUANTITY = 1; Dummy Product product = new Product("Dummy Product"); Dummy State state = new State("West Dakota", "WD"); Dummy City city = new City("Centreville", state); Dummy Address address = new Address("123 Blake St.", city, "12345"); Dummy Customer customer= new Customer("Dummy Customer"); Invoice inv = new Invoice(customer); // Add an item to the invoice inv.addItemQuantity(product, QUANTITY); // Verify that item was inserted List lineItems = inv.getLineItems(); assertEquals("number of items", lineItems.size(), 1); LineItem actual = (LineItem)lineItems.get(0); LineItem expItem = new LineItem(inv, product, QUANTITY); assertLineItemsEqual("",expItem, actual); } 17
  63. 63. Stub• Provê alguns dados estáticos que serão usados nos testes• Não funciona para outras coisas além do que está no teste 18
  64. 64. Stub• Provê alguns dados estáticos que serão usados nos testes• Não funciona para outras coisas além do que está no testeclass OrderStateTester { public void testOrderSendsMailIfUnfilled() { Order order = new Order(TALISKER, 51); order.fill(new Customer("techday@locaweb.com.br")); assertEquals("techday@locaweb.com.br", order.getEmail()); }} 18
  65. 65. Spy• Muito parecido com Stub, mas com a diferença de que “grava” algumas coisas 19
  66. 66. Spy• Muito parecido com Stub, mas com a diferença de que “grava” algumas coisasclass OrderStateTester { public void testOrderSendsMailIfUnfilled() { Order order = new Order(TALISKER, 51); MailServiceSpy mailer = new MailServiceSpy(); order.setMailer(mailer); order.fill(new Customer("techday@locaweb.com.br")); assertEquals(1, mailer.numberSent()); }} 19
  67. 67. Spy• Muito parecido com Stub, mas com a diferença de que “grava” algumas coisasclass OrderStateTester { public void testOrderSendsMailIfUnfilled() { Order order = new Order(TALISKER, 51); MailServiceSpy mailer = new MailServiceSpy(); order.setMailer(mailer); order.fill(new Customer("techday@locaweb.com.br")); assertEquals(1, mailer.numberSent()); }}public class MailServiceSpy implements MailService { private List<Message> messages = new ArrayList<Message>(); public void send(Message msg) { messages.add(msg); } public int numberSent() { return messages.size(); }} 19
  68. 68. O que são Mock Objects? Years later, Mock objects are still quite controversial, often misused and sometimes misunderstood. “Pintside Thoughts: Mock Objects History” —Tim McKinnon
  69. 69. O que são Mock Objects?• Cada pessoa entende de um jeito diferente• Terminologia ambígua• Ficou famoso inicialmente na comunidade JAVA & TDD Comportamento Estado testa interação entre testa o resultado dessas objetos interações
  70. 70. Código Mockpublic class FTPUploaderTest { public void shouldUploadOnePhoneConfig() throws Exception { FTPUtils ftpUtils = createMock(FTPUtils.class); FTPUploader uploader = new FTPUploader(ftpUtils); FTPClient ftpClient = createMock(FTPClient.class); expect(ftpUtils.getFTPConnection()).andReturn(ftpClient); ftpUtils.delete(ftpClient, "/", "file-name.cfg"); ftpUtils.ftpUpload(ftpClient, "/polycom/", "/", "file-name.cfg"); expect(ftpClient.logout()).andReturn(true); expect(ftpClient.isConnected()).andReturn(false); expect(ftpClient.disconnect()); replay(ftpUtils, ftpClient); List<String> fileNames = new ArrayList<String>(); fileNames.add("file-name.cfg"); uploader.sendFTPFiles(fileNames); verify(ftpUtils, ftpClient); }}
  71. 71. Código Mockpublic class FTPUploaderTest { public void shouldUploadOnePhoneConfig() throws Exception { FTPUtils ftpUtils = createMock(FTPUtils.class); FTPUploader uploader = new FTPUploader(ftpUtils); Criação dos Mocks FTPClient ftpClient = createMock(FTPClient.class); expect(ftpUtils.getFTPConnection()).andReturn(ftpClient); ftpUtils.delete(ftpClient, "/", "file-name.cfg"); ftpUtils.ftpUpload(ftpClient, "/polycom/", "/", "file-name.cfg"); expect(ftpClient.logout()).andReturn(true); expect(ftpClient.isConnected()).andReturn(false); expect(ftpClient.disconnect()); replay(ftpUtils, ftpClient); List<String> fileNames = new ArrayList<String>(); fileNames.add("file-name.cfg"); uploader.sendFTPFiles(fileNames); verify(ftpUtils, ftpClient); }}
  72. 72. Código Mockpublic class FTPUploaderTest { public void shouldUploadOnePhoneConfig() throws Exception { FTPUtils ftpUtils = createMock(FTPUtils.class); FTPUploader uploader = new FTPUploader(ftpUtils); Criação dos Mocks FTPClient ftpClient = createMock(FTPClient.class); expect(ftpUtils.getFTPConnection()).andReturn(ftpClient); ftpUtils.delete(ftpClient, "/", "file-name.cfg"); ftpUtils.ftpUpload(ftpClient, "/polycom/", "/", "file-name.cfg"); Gravando expect(ftpClient.logout()).andReturn(true); Comportamentos expect(ftpClient.isConnected()).andReturn(false); expect(ftpClient.disconnect()); replay(ftpUtils, ftpClient); List<String> fileNames = new ArrayList<String>(); fileNames.add("file-name.cfg"); uploader.sendFTPFiles(fileNames); verify(ftpUtils, ftpClient); }}
  73. 73. Código Mockpublic class FTPUploaderTest { public void shouldUploadOnePhoneConfig() throws Exception { FTPUtils ftpUtils = createMock(FTPUtils.class); FTPUploader uploader = new FTPUploader(ftpUtils); Criação dos Mocks FTPClient ftpClient = createMock(FTPClient.class); expect(ftpUtils.getFTPConnection()).andReturn(ftpClient); ftpUtils.delete(ftpClient, "/", "file-name.cfg"); ftpUtils.ftpUpload(ftpClient, "/polycom/", "/", "file-name.cfg"); Gravando expect(ftpClient.logout()).andReturn(true); Comportamentos expect(ftpClient.isConnected()).andReturn(false); expect(ftpClient.disconnect()); replay(ftpUtils, ftpClient); Fim gravação List<String> fileNames = new ArrayList<String>(); fileNames.add("file-name.cfg"); uploader.sendFTPFiles(fileNames); verify(ftpUtils, ftpClient); }}
  74. 74. Código Mockpublic class FTPUploaderTest { public void shouldUploadOnePhoneConfig() throws Exception { FTPUtils ftpUtils = createMock(FTPUtils.class); FTPUploader uploader = new FTPUploader(ftpUtils); Criação dos Mocks FTPClient ftpClient = createMock(FTPClient.class); expect(ftpUtils.getFTPConnection()).andReturn(ftpClient); ftpUtils.delete(ftpClient, "/", "file-name.cfg"); ftpUtils.ftpUpload(ftpClient, "/polycom/", "/", "file-name.cfg"); Gravando expect(ftpClient.logout()).andReturn(true); Comportamentos expect(ftpClient.isConnected()).andReturn(false); expect(ftpClient.disconnect()); replay(ftpUtils, ftpClient); Fim gravação List<String> fileNames = new ArrayList<String>(); fileNames.add("file-name.cfg"); Execução do método uploader.sendFTPFiles(fileNames); a ser testado verify(ftpUtils, ftpClient); }}
  75. 75. Código Mockpublic class FTPUploaderTest { public void shouldUploadOnePhoneConfig() throws Exception { FTPUtils ftpUtils = createMock(FTPUtils.class); FTPUploader uploader = new FTPUploader(ftpUtils); Criação dos Mocks FTPClient ftpClient = createMock(FTPClient.class); expect(ftpUtils.getFTPConnection()).andReturn(ftpClient); ftpUtils.delete(ftpClient, "/", "file-name.cfg"); ftpUtils.ftpUpload(ftpClient, "/polycom/", "/", "file-name.cfg"); Gravando expect(ftpClient.logout()).andReturn(true); Comportamentos expect(ftpClient.isConnected()).andReturn(false); expect(ftpClient.disconnect()); replay(ftpUtils, ftpClient); Fim gravação List<String> fileNames = new ArrayList<String>(); fileNames.add("file-name.cfg"); Execução do método uploader.sendFTPFiles(fileNames); a ser testado verify(ftpUtils, ftpClient); Verificação Final }}
  76. 76. Fake Object• Têm uma implementação completa, mas simples• Não vai para produção• Exemplo: banco de dados em memória 23
  77. 77. Fake Object • Têm uma implementação completa, mas simples • Não vai para produção • Exemplo: banco de dados em memória public void testReadWrite_inMemory() throws Exception { // Setup: FlightMgmtFacadeImpl facade = new FlightMgmtFacadeImpl(); facade.setDao(new InMemoryDatabase()); // Exercise: BigDecimal yyc = facade.createAirport("YYC", "Calgary", "Calgary"); BigDecimal lax = facade.createAirport("LAX", "LAX Intl", "LA"); facade.createFlight(yyc, lax); List flights = facade.getFlightsByOriginAirport(yyc); // Verify: assertEquals("# of flights", 1, flights.size()); Flight flight = (Flight) flights.get(0); assertEquals("origin", yyc, flight.getOrigin().getCode()); } 23
  78. 78. Fake Object • Têm uma implementação completa, mas simples • Não vai para produção • Exemplo: banco de dados em memória public void testReadWrite_inMemory() throws Exception { // Setup: FlightMgmtFacadeImpl facade = new FlightMgmtFacadeImpl(); facade.setDao(new InMemoryDatabase()); // Exercise: Fake BigDecimal yyc = facade.createAirport("YYC", "Calgary", "Calgary"); BigDecimal lax = facade.createAirport("LAX", "LAX Intl", "LA"); facade.createFlight(yyc, lax); List flights = facade.getFlightsByOriginAirport(yyc); // Verify: assertEquals("# of flights", 1, flights.size()); Flight flight = (Flight) flights.get(0); assertEquals("origin", yyc, flight.getOrigin().getCode()); } 23
  79. 79. Implementação de Fake Objectpublic class InMemoryDatabase implements FlightDao{ private List airports = new Vector(); public Airport createAirport(String airportCode, String name, String nearbyCity) throws DataException, InvalidArgumentException { Airport result = new Airport(getNextAirportId(), airportCode, name, createCity(nearbyCity)); airports.add(result); return result; } public Airport getAirportByPrimaryKey(BigDecimal airportId) throws DataException{ for (Airport airport: airports) { if (airport.getId().equals(airportId)) { return airport; } } throw new DataException("Airport not found:"+airportId); }} 24
  80. 80. Mocks nas Linguagens
  81. 81. Mocks nas Linguagens• Java - EasyMock, JMock, Mockito
  82. 82. Mocks nas Linguagens• Java - EasyMock, JMock, Mockito• Ruby - Mocha, RSpec?
  83. 83. Mocks nas Linguagens• Java - EasyMock, JMock, Mockito• Ruby - Mocha, RSpec?• .NET - NMock, Rhino Mocks
  84. 84. Mocks nas Linguagens• Java - EasyMock, JMock, Mockito• Ruby - Mocha, RSpec?• .NET - NMock, Rhino Mocks• Perl - Test::MockObjects
  85. 85. Mocks nas Linguagens• Java - EasyMock, JMock, Mockito• Ruby - Mocha, RSpec?• .NET - NMock, Rhino Mocks• Perl - Test::MockObjects• C++ - Google Mocks
  86. 86. Mocks nas Linguagens• Java - EasyMock, JMock, Mockito• Ruby - Mocha, RSpec?• .NET - NMock, Rhino Mocks• Perl - Test::MockObjects• C++ - Google Mocks• PHP - Simple Test for PHP
  87. 87. Testes com Doubles - Recapitulando DoubleDummy Stub Spy Mock FakeObject 26
  88. 88. Testes com Doubles - Recapitulando DoubleDummy Stub Spy Mock FakeObject Preencheparâmetros 26
  89. 89. Testes com Doubles - Recapitulando DoubleDummy Stub Spy Mock FakeObject Provê Preenche dados paraparâmetros os testes 26
  90. 90. Testes com Doubles - Recapitulando DoubleDummy Stub Spy Mock FakeObject Provê Provê Preenche dados para dados eparâmetros os testes grava 26
  91. 91. Testes com Doubles - Recapitulando DoubleDummy Stub Spy Mock FakeObject Provê Provê Verifica Preenche dados para dados e comporta-parâmetros os testes grava mentos 26
  92. 92. Testes com Doubles - Recapitulando DoubleDummy Stub Spy Mock FakeObject Provê Provê Verifica Implemen- Preenche dados para dados e comporta- taçãoparâmetros os testes grava mentos +simples 26
  93. 93. QuizDublês + Injeção de Dependência =
  94. 94. QuizDublês + Injeção de Dependência = Testes
  95. 95. Referências• http://www.springframework.org/documentation• http://martinfowler.com/articles/injection.html• http://martinfowler.com/articles/mocksArentStubs.html• http://xunitpatterns.com/• Anil Hemrajani, Agile Java Development with Spring, Hibernate and Eclipse
  96. 96. Para aqueles que buscam sucesso em projetos e negócios, LOCAWEB oferece soluções inovadoras em Hosted IT Services de alta performance e confiabilidade. Data Center - Av. Juscelino Kubitschek, 1830, 10º andar – Itaim Bibi – São Paulo – SP Escritório SP - Av. Juscelino Kubitschek, 1830, 10º andar – Itaim Bibi – São Paulo – SP | (11) 3544-0400 Escritório RS - Av. Carlos Gomes, 1340, 6º andar – Auxiliadora – Porto Alegre – RS | (51) 4062-0203 0800 726 7770 - Demais Estados

×