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

3,199 views
3,070 views

Published on

1 Comment
2 Likes
Statistics
Notes
No Downloads
Views
Total views
3,199
On SlideShare
0
From Embeds
0
Number of Embeds
1,448
Actions
Shares
0
Downloads
21
Comments
1
Likes
2
Embeds 0
No embeds

No notes for slide
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • 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

    ×