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

Nenhum comentário:

Postar um comentário