domingo, 31 de agosto de 2014

Fica a Dica - Testando chamadas a funções de uma DLL usando PowerMock, EasyMock, JUnit e JNA no Java com TDD

Estava trabalhando no projeto Quantis, fazendo sua integração com Trader Gráfico para envio de ordens para a Bovespa quando surgiu a necessidade de testar as chamadas as funções da DLL de integração que eu já havia desenvolvido anteriormente em Delphi e que é a responsável pela a comunicação com o roteador de ordens, através da API do Windows.

Como essa biblioteca tem um funcionamento independente do Quantis e já havia sido testada na plataforma que foi criada, era necessário apenas fazer os testes para validar as precondições dos parâmetros de entrada dos métodos e simular falhas de comunicação com o roteador de ordens do  Trader Gráfico. O problema é como fazer isso sem fazer as chamadas aos métodos da DLL? Simples, usando Mocks!!!

Para quem não conhece, mocks são objetos que simulam o comportamento de outros objetos, sendo muito utilizados para realização de testes em TDD. Deste modo era necessário criar um Mock que emula-se o comportamento da minha DLL. Como a integração com essa api foi feita utilizando JNA (se você nunca ouviu falar em JNA, recomendo a leitura desse artigo no blog da Caelum) isso foi muito fácil, pois foi necessário apenas implementar a interface de integração com a DLL. O código da listagem 1 representa a interface, o da listagem 2 representa a implementação do Mock.

Listagem 1:

Listagem 2:
Tendo feito isso, é necessário substituir a chamada ao método de carregamento da DLL para que ele carregue nosso mock. No caso, isso estava sendo feito na criação do serviço utilizado para fazer as chamadas aos métodos da DLL (linha 13 da Listagem 3) sendo o carregamento feito através da chamada ao método estático loadLibrary da classe Native da JNA.

Existem diversos frameworks para trabalhar com mocks (Mockito, EasyMock, MockCreator, etc.), contudo nenhum deles permite a substituição de um método estático, pois para fazer isso é necessário a manipulação de bytecode Java!!!! O bom é que não precisamos nos preocupar pois o framework PowerMock faz exatamente isso. Ele também é integrado ao Mockito e ao Easy Mock o que permite a utilização deles para fazer as substituições das classes pelos mocks em nossos testes (No caso, utilizamos o EasyMock). Bom, e como fazer isso? Simples, veja a listagem 4. Nela temos um exemplo da classe  utilizada para fazer os testes onde destacamos as seguintes anotações.
  • @RunWith(PowerMockRunner.class): anotação usada para indicar qual classe deve ser utilizada pelo JUnit para executar os testes.
  • @PrepareForTest({Native.class}): Indica quais classes devem ser "preparadas" para os testes, ou seja, quais classes tem métodos que serão chamados ou campos que serão substituídos.
  • @SuppressStaticInitializationFor("com.sun.jna.Native"):  Essa anotação não é obrigatória, contudo deve ser utilizada devido a uma exceção levantada pelo EasyMock ao carregar a DLL (Exeção 1).
Para que o método  loadLibrary seja trocado é necessário indicar qual classe possui os métodos estáticos que devem ser substituídos, isso é feito pelo método PowerMock.mockStatic(Native.class), linha 22 da listagem 4. Na sequencia chamamos o EasyMock para indicar que as chamadas ao método loadLibrary devem retornar o nosso mock (linha 24 da listagem 4). Em seguida chamamos PowerMock.replay(Native.class) que realiza a substituição do método loadLibrary na classe Native.class (linha 25 da listagem 4). Em fim é criado o objeto ServicoDeIntegracao que será utilizado nos testes e que vai ter a DLL de integração substituída pelo mock!!! Pronto agora é só criar os testes!!!

Se você utiliza o Maven, a listagem 5 tem todas as dependências necessárias para utilizar o PowerMock com Easy Mock. Também disponibilizei as dependências para a JNA. Qualquer dúvida deixe um comentário!

Listagem 3:
Listagem 4:
Listagem 5:
Exceção 1: (Utilize a anotação  @SuppressStaticInitializationFor("com.sun.jna.Native") para evita-la):

Nenhum comentário:

Postar um comentário