Mostrando postagens com marcador Testes. Mostrar todas as postagens
Mostrando postagens com marcador Testes. Mostrar todas as postagens

terça-feira, 5 de junho de 2012

Mocks com Mockito - parte 2

Para continuar nosso "papo" sobre Mocks vou apresentar mais algumas funções do Mockito

Como talvez você já tenha percebido o mockito não serve só para mocks, mas serve também para testar o comportamento da classe que está sob teste com suas dependências.

Usando o mesmo exemplo da nossa classe que envia mensagens. Imagine agora que temos um novo métod que recebe uma ou várias mensagens e as envia usando o objeto connection.

Usando o Mockito podemos escrever um teste como o abaixo.

import static org.mockito.Mockito.*;
//class declaration bla bla bla.
@Test
public void behaviourTest() {
  Connection connection = mock(Connection.class);
  
  MyMessageSender messageSender = new MyMessageSender(connection);
  
  messageSender.sendMultipleMessages("Mensagem 1", "Mensagem 2");
  
  verify(connection, times(2)).sendMessage(anyString());
}


Traduzindo a Linha 11:
  • Verificar que o método sendMessage com o argumento...
    • uma string qualquer
  • foi chamada duas vezes

O Mockito também possibilita simular o retorno de mensagens.

Para demonstrar isto criaremos um novo para sabe se a nossa classe está recebendo as mensagens corretamente, nesse caso ao invés de usar o mock para testar a passagem de parâmetros para ele teremos que usa-lo para simular os retornos de seus métodos.

Testaremos a classe MyMessageReader que se parece com a seguinte classe.

public class MyMessageReader {
  private Connection connection;
  
  public MyMessageReader(Connection connection) {
    this.connection = connection;
  }

  public String readMessage() { 
   return connection.readMessage();
  }
}

Novamente nossa classe sob teste usa um objeto Connection, mas desta vez o método que chamamos é connection.readMessage()

Nosso teste então terá que simular um retorno de connection.readMessage(), usando o Mockito ficaria como o código abaixo.

@Test
public void readMessageTest() {
  connection = mock(Connection.class);
  
  given(connection.readMessage()).willReturn("minhaMensagem");
  myMessageReader = new MyMessageReader(connection);
  
  String readedMessage = myMessageReader.readMessage();
  
  assertEquals(readedMessage, "minhaMensagem");
}

Claro que como tudo em programação existe mais de uma maneira simular os retornos de chamados dos métodos, as duas linhas seguintes são equivalentes.

given(connection.readMessage()).willReturn("minhaMensagem");
when(connection.readMessage()).thenReturn("minhaMensagem");

A primeira linha tem uma abordagem mais em linha com BDD, tanto que o método given é da classe BDDMockito.

Caso o método que simulamos o retorno receba um parâmetro podemos definir diferentes tipos de retorno para diferentes parâmetros, como no exemplo abaixo.

Map map = mock(Map.class);
given(map.get(anyString())).willReturn(null);
given(map.get("chave1")).willReturn("valor1");

map.get("chave1"); //retorna string "valor1"
map.get("outraChave");//retorna nulo

No próximo post de Mocks mostrarei como usar Spies em seus testes com Mock.

Se quiser o código completo pode pegar no git hub.
https://github.com/diegoy/talks-mockito

Valeu!

Mais:
Mocks com Mockito, parte 3

domingo, 3 de junho de 2012

Mocks com Mockito

Desta vez vamos ter uma breve introdução ao uso de Mocks em seus testes.

Há vários benefícios que o uso de testes unitários podem trazer, eu pessoalmente gosto muito de ter testes pois ajuda muito na hora de refatorar seu código e ter a certeza de que o seu funcionamento não mudou, escrever os testes também nos ajuda a identificar casos em que o código está com um alto acoplamento.

Usando TDD ou não os testes são importantes mas podem ser muito difícil de escreve-los

Muitas vezes ao tentar escrever testes para algumas classes temos alguns desafios.
Um Software geralmente depende de vários outros sistemas para funcionar, por exemplo uma base de dados, levando isso em conta os testes de classes que se comunicam com a base de dados são mais difíceis de escrever e o uso de um framework de mocks pode ajudar muito! 

Neste artigo vamos falar do Mockito, que é um framework de mocks criado para a linguagem Java (há versões para outras linguagens). 

A instalação é simples, baixe o jar no site do mockito, coloque-o no seu classpath e pronto! Ou se preferir configure no dependencies de seu maven :)

Suponha que em seu código você tenha uma classe que seja responsável por enviar mensagens através de um socket, aqui vou chama-la de MyMessageSender, sua classe tem como regra enviar mensagens somente com letras maiúsculas.

public class MyMessageSender {
 
  private Connection connection;

  public MyMessageSender(Connection connection) {
    this.connection = connection;
  }

  public void send(String string) {
    connection.sendMessage(string.toUpperCase());
  } 
}

No construtor da classe MyMessageSender passamos como parâmetro um objeto do tipo Connection. Esse objeto possui a conexão do socket e também possui um método sendMessage que escreve uma mensagem no socket.

Para fazer o teste unitário desta classe necessitaríamos instanciar a classe connection para passarmos à classe testada.
 
public class Connection {

  // declaracao dos atributos

  public Connection(String hostAddress, int port) {
    super();
    
    this.hostAddress = hostAddress;
    this.port = port;
  }
 
  public boolean connect() {
    try {
      socket = new Socket(hostAddress, port);
      printStream = getPrintStream(); //abre um output stream
      inputStreamReader = getOutputStream(); //abre um input stream
      return true;
    } catch (UnknownHostException e) {
      e.printStackTrace();
    } catch (IOException e) {
      e.printStackTrace();
    }
  
    return false;
  }
 
  public void sendMessage(String message) {
    printStream.print(message);
    printStream.flush();
  }
}

Vendo a classe Connection perceba que será um pouco trabalhoso instancia-la dentro do teste, pois ela se conecta a um sistema externo, levando isso em conta precisaríamos também criar um mock desse sistema externo para testarmos adequadamente a nossa classe. E consequentemente estaríamos testando muito mais que somente nossa classe MyMessageSender.

Usando o Mockito podemos facilmente criar um mock de Connection para usar em nosso teste sem termos que nos preocupar com as conexões que são necessárias a classe Connection.

@Test
public void sendMessageTest() {
 Connection connection = Mockito.mock(Connection.class);
 
 MyMessageSender messageSender = new MyMessageSender(connection);
 
 messageSender.send("Uma mensagem");
 Mockito.verify(connection).sendmessage("UMA MENSAGEM");
}

Na linha 3 criamos um mock da classe Connection.

Na linha 8 colocamos uma verificamos que o método sendmessage do objeto connection foi chamado passando como parâmetro a string "UMA MENSAGEM". Qualquer string diferente da informada na linha do verify vai causar uma falha no teste.

Assim conseguimos garantir o correto funcionamento da classe MyMessageSender sem precisar ficar criando uma instância real da classe Connection.

No próximo post escreverei como o Mockito pode te ajudar para simular respostas de métodos.

Código fonte disponível no meu github
https://github.com/diegoy/talks-mockito

Mais:
Mocks com Mockito, parte 2
Mocks com Mockito, parte 3