SlideShare une entreprise Scribd logo
1  sur  96
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)
Exemplo
public 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
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
Dependência


• PhoneLister depende da interface e da implementação
• Como depender somente da interface?




                                                        5
Idéia Básica - Injeção




                         Injeção


                                   Framework
                                   Injeção de
                                   Dependência




                                                 6
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
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
Usando na aplicação
public 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
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
Fábrica de Objetos




                     10
Fábrica de Objetos

                     Repositório


                        S          P




      Cliente 1                        Cliente 2




                                                   10
Fábrica de Objetos

                     Repositório


                        S          P




      Cliente 1                        Cliente 2


        S1




                                                   10
Fábrica de Objetos

                       Repositório


                          S          P




      Cliente 1                          Cliente 2


        S1        S1




                                                     10
Fábrica de Objetos

                       Repositório


                          S          P




      Cliente 1                          Cliente 2


        S1        S1             S1




                                                     10
Fábrica de Objetos

                            Repositório


                               S          P




      Cliente 1                               Cliente 2


        S1        S1   P1             S1




                                                          10
Fábrica de Objetos

                            Repositório


                               S          P




      Cliente 1                                Cliente 2


        S1        S1   P1             S1      P2




                                                           10
Fábrica de Objetos

                            Repositório


                               S          P




      Cliente 1                                Cliente 2


        S1        S1   P1             S1      P2    P3




                                                           10
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 propriedades desejadas usando os
  setters




                                                              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 propriedades desejadas usando os
  setters
• Facilita boas práticas de programação: uso de interfaces no
  lugar de classes




                                                                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 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
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
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
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




                                           12
Frameworks para todas as linguagens


• Java - Spring, PicoContainer, HiveMind
• PHP - DIContainer
• .NET - Spring.NET, PicoContainer.NET




                                           12
Frameworks para todas as linguagens


•   Java - Spring, PicoContainer, HiveMind
•   PHP - DIContainer
•   .NET - Spring.NET, PicoContainer.NET
•   Python - PyContainer, Spring Python




                                             12
Frameworks para todas as linguagens


•   Java - Spring, PicoContainer, HiveMind
•   PHP - DIContainer
•   .NET - Spring.NET, PicoContainer.NET
•   Python - PyContainer, Spring Python
•   Ruby - Needle




                                             12
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
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
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
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
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 campos imutáveis de serem
  alterados
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 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
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
Voltando ao nosso PhoneLister
public 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
Voltando ao nosso PhoneLister
public 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
Voltando ao nosso PhoneLister
public 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
Voltando ao nosso PhoneLister
public 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
Voltando ao nosso PhoneLister
public 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
Voltando ao nosso PhoneLister
public 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
Voltando ao nosso PhoneLister
public 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
Testes com Dublês (Doubles)


                  Double




                              16
Testes com Dublês (Doubles)


                  Double




                              16
Testes com Dublês (Doubles)


                   Double




Dummy
Object




                               16
Testes com Dublês (Doubles)


                   Double




Dummy
          Stub
Object




                               16
Testes com Dublês (Doubles)


                   Double




Dummy
          Stub      Spy
Object




                               16
Testes com Dublês (Doubles)


                   Double




Dummy
          Stub      Spy        Mock
Object




                                      16
Testes com Dublês (Doubles)


                   Double




Dummy
          Stub      Spy        Mock   Fake
Object




                                             16
Dummy Object

•   Objetos que nunca são usados, só servem para preencher parâmetros




                                                                        17
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
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
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
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
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
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
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
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

class 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
Spy
•   Muito parecido com Stub, mas com a diferença de que “grava” algumas coisas




                                                                                 19
Spy
•   Muito parecido com Stub, mas com a diferença de que “grava” algumas coisas
class 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
Spy
•   Muito parecido com Stub, mas com a diferença de que “grava” algumas coisas
class 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
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
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
Código Mock
public 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);
    }

}
Código Mock
public 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);
    }

}
Código Mock
public 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);
    }

}
Código Mock
public 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);
    }

}
Código Mock
public 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);
    }

}
Código Mock
public 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
    }

}
Fake Object

•   Têm uma implementação completa, mas simples
•   Não vai para produção
•   Exemplo: banco de dados em memória




                                                  23
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
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
Implementação de Fake Object
public 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
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 - Test::MockObjects
Mocks nas Linguagens


•   Java - EasyMock, JMock, Mockito
•   Ruby - Mocha, RSpec?
•   .NET - NMock, Rhino Mocks
•   Perl - Test::MockObjects
•   C++ - Google Mocks
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
Testes com Doubles - Recapitulando


                   Double




Dummy
          Stub      Spy      Mock     Fake
Object




                                             26
Testes com Doubles - Recapitulando


                    Double




Dummy
             Stub    Spy      Mock     Fake
Object



 Preenche
parâmetros




                                              26
Testes com Doubles - Recapitulando


                          Double




Dummy
               Stub        Spy     Mock   Fake
Object



                Provê
 Preenche
             dados para
parâmetros
              os testes




                                                 26
Testes com Doubles - Recapitulando


                          Double




Dummy
               Stub        Spy      Mock   Fake
Object



                Provê      Provê
 Preenche
             dados para   dados e
parâmetros
              os testes    grava




                                                  26
Testes com Doubles - Recapitulando


                          Double




Dummy
               Stub        Spy       Mock        Fake
Object



                Provê      Provê      Verifica
 Preenche
             dados para   dados e   comporta-
parâmetros
              os testes    grava     mentos




                                                        26
Testes com Doubles - Recapitulando


                          Double




Dummy
               Stub        Spy       Mock         Fake
Object



                Provê      Provê      Verifica   Implemen-
 Preenche
             dados para   dados e   comporta-      tação
parâmetros
              os testes    grava     mentos       +simples




                                                             26
Quiz




Dublês + Injeção de Dependência =
Quiz




Dublês + Injeção de Dependência = Testes
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
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

Contenu connexe

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

Sistemas Distribuídos - Comunicação Distribuída – CORBA
Sistemas Distribuídos - Comunicação Distribuída – CORBASistemas Distribuídos - Comunicação Distribuída – CORBA
Sistemas Distribuídos - Comunicação Distribuída – CORBA
Adriano Teixeira de Souza
 
Aspect-oriented Programming (AOP) com PostSharp
Aspect-oriented Programming (AOP) com PostSharpAspect-oriented Programming (AOP) com PostSharp
Aspect-oriented Programming (AOP) com PostSharp
Comunidade NetPonto
 
Sistemas distribuídos com RMI
Sistemas distribuídos com RMISistemas distribuídos com RMI
Sistemas distribuídos com RMI
Charleston Anjos
 
Integração com webservices usando MVC e mágica
Integração com webservices usando MVC e mágicaIntegração com webservices usando MVC e mágica
Integração com webservices usando MVC e mágica
Leocadio Tiné
 

Similaire à Injeção de Dependência e Testes com Dublês (20)

Conceitos Básicos de Objetos Distribuidos
Conceitos Básicos de Objetos DistribuidosConceitos Básicos de Objetos Distribuidos
Conceitos Básicos de Objetos Distribuidos
 
RAD Studio 10.2 Tokyo
RAD Studio 10.2 TokyoRAD Studio 10.2 Tokyo
RAD Studio 10.2 Tokyo
 
Sistemas Distribuídos - Comunicação Distribuída – CORBA
Sistemas Distribuídos - Comunicação Distribuída – CORBASistemas Distribuídos - Comunicação Distribuída – CORBA
Sistemas Distribuídos - Comunicação Distribuída – CORBA
 
JHipster - Produtividade e Maturidade em suas mãos
JHipster - Produtividade e Maturidade em suas mãosJHipster - Produtividade e Maturidade em suas mãos
JHipster - Produtividade e Maturidade em suas mãos
 
Aplicativos hibridos-com-ionic-voce-tambem-pode-comecar-a-desenvolver-agora-t...
Aplicativos hibridos-com-ionic-voce-tambem-pode-comecar-a-desenvolver-agora-t...Aplicativos hibridos-com-ionic-voce-tambem-pode-comecar-a-desenvolver-agora-t...
Aplicativos hibridos-com-ionic-voce-tambem-pode-comecar-a-desenvolver-agora-t...
 
Python - Programando em alto nível
Python - Programando em alto nívelPython - Programando em alto nível
Python - Programando em alto nível
 
Spring e Injeção de Dependência
Spring e Injeção de DependênciaSpring e Injeção de Dependência
Spring e Injeção de Dependência
 
TDC2017 | São Paulo - Trilha Mobile How we figured out we had a SRE team at -...
TDC2017 | São Paulo - Trilha Mobile How we figured out we had a SRE team at -...TDC2017 | São Paulo - Trilha Mobile How we figured out we had a SRE team at -...
TDC2017 | São Paulo - Trilha Mobile How we figured out we had a SRE team at -...
 
Aspect-oriented Programming (AOP) com PostSharp
Aspect-oriented Programming (AOP) com PostSharpAspect-oriented Programming (AOP) com PostSharp
Aspect-oriented Programming (AOP) com PostSharp
 
12 factor app. Melhor com Docker
12 factor app. Melhor com Docker12 factor app. Melhor com Docker
12 factor app. Melhor com Docker
 
Sistemas distribuídos com RMI
Sistemas distribuídos com RMISistemas distribuídos com RMI
Sistemas distribuídos com RMI
 
Pyramid - O Framework Web para Todos
Pyramid - O Framework Web para TodosPyramid - O Framework Web para Todos
Pyramid - O Framework Web para Todos
 
Infraestrutura Imutável - Agile Trends
Infraestrutura Imutável - Agile TrendsInfraestrutura Imutável - Agile Trends
Infraestrutura Imutável - Agile Trends
 
Dev401 novos recursos do microsoft visual basic 2010
Dev401 novos recursos do microsoft visual basic 2010Dev401 novos recursos do microsoft visual basic 2010
Dev401 novos recursos do microsoft visual basic 2010
 
Ionic 2 na pratica!
Ionic 2 na pratica!Ionic 2 na pratica!
Ionic 2 na pratica!
 
Iniciando o desenvolvimento de aplicativos híbridos com VS Code + Ionic + Typ...
Iniciando o desenvolvimento de aplicativos híbridos com VS Code + Ionic + Typ...Iniciando o desenvolvimento de aplicativos híbridos com VS Code + Ionic + Typ...
Iniciando o desenvolvimento de aplicativos híbridos com VS Code + Ionic + Typ...
 
TDC2016SP - O que há de novo no Entity Framework Core 1.0
TDC2016SP - O que há de novo no Entity Framework Core 1.0TDC2016SP - O que há de novo no Entity Framework Core 1.0
TDC2016SP - O que há de novo no Entity Framework Core 1.0
 
Entity Framework 7.0 a.k.a Entity Core 1.0
Entity Framework 7.0 a.k.a Entity Core 1.0Entity Framework 7.0 a.k.a Entity Core 1.0
Entity Framework 7.0 a.k.a Entity Core 1.0
 
Integração com webservices usando MVC e mágica
Integração com webservices usando MVC e mágicaIntegração com webservices usando MVC e mágica
Integração com webservices usando MVC e mágica
 
Java CDI: Usando Java CDI em projetos Jakarta EE ou Microprofile
Java CDI: Usando Java CDI em projetos Jakarta EE ou MicroprofileJava CDI: Usando Java CDI em projetos Jakarta EE ou Microprofile
Java CDI: Usando Java CDI em projetos Jakarta EE ou Microprofile
 

Plus de Daniel Cukier

When Should You Consider Meta Architectures
When Should You Consider Meta ArchitecturesWhen Should You Consider Meta Architectures
When Should You Consider Meta Architectures
Daniel Cukier
 

Plus de Daniel Cukier (20)

Solidity: Zero to Hero Corporate Training
Solidity: Zero to Hero Corporate TrainingSolidity: Zero to Hero Corporate Training
Solidity: Zero to Hero Corporate Training
 
Pair programming
Pair programmingPair programming
Pair programming
 
Eficiency and Low Cost: Pro Tips for you to save 50% of your money with Googl...
Eficiency and Low Cost: Pro Tips for you to save 50% of your money with Googl...Eficiency and Low Cost: Pro Tips for you to save 50% of your money with Googl...
Eficiency and Low Cost: Pro Tips for you to save 50% of your money with Googl...
 
Startup Communities: From Nascence to Maturity
Startup Communities: From Nascence to MaturityStartup Communities: From Nascence to Maturity
Startup Communities: From Nascence to Maturity
 
Technology Startups Ecosystem in China - Lessons to other ecosystems
Technology Startups  Ecosystem in China - Lessons to other ecosystemsTechnology Startups  Ecosystem in China - Lessons to other ecosystems
Technology Startups Ecosystem in China - Lessons to other ecosystems
 
Software Startup Ecosystems Evolution - The New York City Case Study
Software Startup Ecosystems Evolution - The New York City Case StudySoftware Startup Ecosystems Evolution - The New York City Case Study
Software Startup Ecosystems Evolution - The New York City Case Study
 
Maturity model for Startup Ecosystems
Maturity model for Startup EcosystemsMaturity model for Startup Ecosystems
Maturity model for Startup Ecosystems
 
Why Google Cloud is so special? Stories from a cloud user
Why Google Cloud is so special?  Stories from a cloud userWhy Google Cloud is so special?  Stories from a cloud user
Why Google Cloud is so special? Stories from a cloud user
 
Software Architectures for a Single Person Team
Software Architectures for a Single Person TeamSoftware Architectures for a Single Person Team
Software Architectures for a Single Person Team
 
Startup Communities
Startup CommunitiesStartup Communities
Startup Communities
 
Introduction to Functional Programming with Scala
Introduction to Functional Programming with ScalaIntroduction to Functional Programming with Scala
Introduction to Functional Programming with Scala
 
Play vs Rails
Play vs RailsPlay vs Rails
Play vs Rails
 
O dia a dia de uma Startup
O dia a dia de uma StartupO dia a dia de uma Startup
O dia a dia de uma Startup
 
Selecting Empirical Methods for Software Engineering
Selecting Empirical Methods for Software EngineeringSelecting Empirical Methods for Software Engineering
Selecting Empirical Methods for Software Engineering
 
Is Computer Science Science?
Is Computer Science Science?Is Computer Science Science?
Is Computer Science Science?
 
Ruby Robots
Ruby RobotsRuby Robots
Ruby Robots
 
Better Science Through Art
Better Science Through ArtBetter Science Through Art
Better Science Through Art
 
Designed as Designer
Designed as DesignerDesigned as Designer
Designed as Designer
 
When Should You Consider Meta Architectures
When Should You Consider Meta ArchitecturesWhen Should You Consider Meta Architectures
When Should You Consider Meta Architectures
 
Coding Dojo
Coding DojoCoding Dojo
Coding Dojo
 

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

  • 1. Injeção de Dependência e Testes com Dublês 2º Locaweb Tec Day 04.02.2009
  • 2. Conteúdo • Exemplo • Injeção de Dependência (DI) • Testes com Dublês (Doubles)
  • 3. Exemplo public 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. 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. Dependência • PhoneLister depende da interface e da implementação • Como depender somente da interface? 5
  • 6. Idéia Básica - Injeção Injeção Framework Injeção de Dependência 6
  • 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. 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. Usando na aplicação public 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. 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
  • 12. Fábrica de Objetos Repositório S P Cliente 1 Cliente 2 10
  • 13. Fábrica de Objetos Repositório S P Cliente 1 Cliente 2 S1 10
  • 14. Fábrica de Objetos Repositório S P Cliente 1 Cliente 2 S1 S1 10
  • 15. Fábrica de Objetos Repositório S P Cliente 1 Cliente 2 S1 S1 S1 10
  • 16. Fábrica de Objetos Repositório S P Cliente 1 Cliente 2 S1 S1 P1 S1 10
  • 17. Fábrica de Objetos Repositório S P Cliente 1 Cliente 2 S1 S1 P1 S1 P2 10
  • 18. Fábrica de Objetos Repositório S P Cliente 1 Cliente 2 S1 S1 P1 S1 P2 P3 10
  • 19. Vantagens de usar Injeção de Dependência 11
  • 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. 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. 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. 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. 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. Frameworks para todas as linguagens 12
  • 26. Frameworks para todas as linguagens • Java - Spring, PicoContainer, HiveMind 12
  • 27. Frameworks para todas as linguagens • Java - Spring, PicoContainer, HiveMind • PHP - DIContainer 12
  • 28. Frameworks para todas as linguagens • Java - Spring, PicoContainer, HiveMind • PHP - DIContainer • .NET - Spring.NET, PicoContainer.NET 12
  • 29. Frameworks para todas as linguagens • Java - Spring, PicoContainer, HiveMind • PHP - DIContainer • .NET - Spring.NET, PicoContainer.NET • Python - PyContainer, Spring Python 12
  • 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. 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. 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. 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. 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. DI – Linha do Tempo
  • 37. Construtor ou Setter? • Construtor com parâmetros deixa claro o que é preciso para criar o objeto
  • 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. 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. 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. 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. Voltando ao nosso PhoneLister public 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. Voltando ao nosso PhoneLister public 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. Voltando ao nosso PhoneLister public 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. Voltando ao nosso PhoneLister public 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. Voltando ao nosso PhoneLister public 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. Voltando ao nosso PhoneLister public 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. Voltando ao nosso PhoneLister public 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. Testes com Dublês (Doubles) Double 16
  • 50. Testes com Dublês (Doubles) Double 16
  • 51. Testes com Dublês (Doubles) Double Dummy Object 16
  • 52. Testes com Dublês (Doubles) Double Dummy Stub Object 16
  • 53. Testes com Dublês (Doubles) Double Dummy Stub Spy Object 16
  • 54. Testes com Dublês (Doubles) Double Dummy Stub Spy Mock Object 16
  • 55. Testes com Dublês (Doubles) Double Dummy Stub Spy Mock Fake Object 16
  • 56. Dummy Object • Objetos que nunca são usados, só servem para preencher parâmetros 17
  • 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. 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. 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. 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. 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. 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. 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. 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 class 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. Spy • Muito parecido com Stub, mas com a diferença de que “grava” algumas coisas 19
  • 66. Spy • Muito parecido com Stub, mas com a diferença de que “grava” algumas coisas class 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. Spy • Muito parecido com Stub, mas com a diferença de que “grava” algumas coisas class 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. 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. 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. Código Mock public 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. Código Mock public 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. Código Mock public 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. Código Mock public 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. Código Mock public 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. Código Mock public 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. 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. 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. 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. Implementação de Fake Object public 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
  • 81. Mocks nas Linguagens • Java - EasyMock, JMock, Mockito
  • 82. Mocks nas Linguagens • Java - EasyMock, JMock, Mockito • Ruby - Mocha, RSpec?
  • 83. Mocks nas Linguagens • Java - EasyMock, JMock, Mockito • Ruby - Mocha, RSpec? • .NET - NMock, Rhino Mocks
  • 84. Mocks nas Linguagens • Java - EasyMock, JMock, Mockito • Ruby - Mocha, RSpec? • .NET - NMock, Rhino Mocks • Perl - Test::MockObjects
  • 85. Mocks nas Linguagens • Java - EasyMock, JMock, Mockito • Ruby - Mocha, RSpec? • .NET - NMock, Rhino Mocks • Perl - Test::MockObjects • C++ - Google Mocks
  • 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. Testes com Doubles - Recapitulando Double Dummy Stub Spy Mock Fake Object 26
  • 88. Testes com Doubles - Recapitulando Double Dummy Stub Spy Mock Fake Object Preenche parâmetros 26
  • 89. Testes com Doubles - Recapitulando Double Dummy Stub Spy Mock Fake Object Provê Preenche dados para parâmetros os testes 26
  • 90. Testes com Doubles - Recapitulando Double Dummy Stub Spy Mock Fake Object Provê Provê Preenche dados para dados e parâmetros os testes grava 26
  • 91. Testes com Doubles - Recapitulando Double Dummy Stub Spy Mock Fake Object Provê Provê Verifica Preenche dados para dados e comporta- parâmetros os testes grava mentos 26
  • 92. Testes com Doubles - Recapitulando Double Dummy Stub Spy Mock Fake Object Provê Provê Verifica Implemen- Preenche dados para dados e comporta- tação parâmetros os testes grava mentos +simples 26
  • 93. Quiz Dublês + Injeção de Dependência =
  • 94. Quiz Dublês + Injeção de Dependência = Testes
  • 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. 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

Notes de l'éditeur

  1. \n
  2. \n
  3. \n
  4. \n
  5. \n
  6. \n
  7. \n
  8. \n
  9. \n
  10. \n
  11. \n
  12. \n
  13. \n
  14. \n
  15. \n
  16. \n
  17. \n
  18. \n
  19. \n
  20. \n
  21. \n
  22. \n
  23. \n
  24. \n
  25. \n
  26. \n
  27. \n
  28. \n
  29. \n
  30. \n
  31. \n
  32. \n
  33. \n
  34. \n
  35. \n
  36. \n
  37. \n
  38. \n
  39. \n
  40. \n
  41. \n
  42. \n
  43. \n
  44. \n
  45. \n
  46. \n
  47. \n
  48. \n
  49. \n
  50. \n
  51. \n
  52. \n
  53. \n
  54. \n
  55. \n
  56. \n
  57. \n
  58. \n
  59. \n
  60. \n
  61. \n
  62. \n
  63. \n
  64. \n
  65. \n
  66. \n
  67. \n
  68. \n
  69. \n
  70. \n
  71. \n
  72. \n
  73. \n
  74. \n
  75. \n
  76. \n
  77. \n
  78. \n
  79. \n
  80. \n
  81. \n
  82. \n