JMock – trabalhando com mock objets em java

Lendo sobre testes unitarios, imagine o caso onde o seu teste é complexo: um objeto que chama outro e, então, realiza as suas tarefas. Um bom caso é um DAO que acessa o banco de dados para fazer alguma coisa: se vc pensa em testar esse codigo de forma unitaria teria que subir um banco de testes e, se encontrasse um problema, poderia ser dificil dizer se é problema do DAO ou dos objetos que ele depende (como a conexão com o banco, ou o banco em si).

A solução para estes casos pode ser trabalhar com mocks: objetos “burros” que podem não ter nenhuma função alem de responder ao que vc especificou. A abordagem mais utilizada é vc programar estes objetos para responder a um ou mais metodos com argumentos especificos, assim como as respostas esperadas. No caso do DAO eu posso esperar um determinado SQL e especificar uma determinada resposta, tudo de acordo com o meu cenario de teste.

É claro que Mock Objects em excesso podem atrapalhar, mas é tudo uma questão de bom senso: costumo dizer para quem esta começando a focar os testes nas partes mais importantes do sistema, o core do modelo e regras de negocio e, então, incrementar estas praticas caso veja necessidade. Sem falar que volta e meia surge algo novo.

Para java existe o excelente framework JMock. Logo de cara o site oficial traz um exemplo de como utilizar um mock bem simples (incluindo a integração do mesmo com JUnit 4)

http://www.jmock.org/getting-started.html

Para entender, imagine esta interface

interface Subscriber {
    void receive(String message);
}

Imagine que eu tenho um objeto do tipo Publisher que, ao invocar o metodo publish(message), ele envie esta mensagem para um Subscriber (que recebe com o metodo acima). Para testar o publish eu teria que me certificar que o metodo receive deste objeto Subscriber foi invocado com a mensagem especificada, mais ou menos assim:

import org.jmock.integration.junit4.JMock;
import org.jmock.integration.junit4.JUnit4Mockery;
import org.jmock.Expectations;
 
@RunWith(JMock.class)
class PublisherTest {
    Mockery context = new JUnit4Mockery();
 
    @Test
    public void oneSubscriberReceivesAMessage() {
        // set up
        final Subscriber subscriber = context.mock(Subscriber.class);
 
        Publisher publisher = new Publisher(); // objeto que vou testar
        publisher.add(subscriber); // tenho que adicionar o mock!
 
        final String message = "message";
 
        // aqui eu programo o que eu espero do teste
        context.checking(new Expectations() {{
            oneOf (subscriber).receive(message);
        }});
 
        // aqui eu executo!
        publisher.publish(message);
    }
}

Facil?

Algoritmos Geneticos, Videos e VBScript

O Carlo “zED” Caputo ja tinha comentado sobre o uso de Algoritimo Genético para melhorar a qualidade dos vídeos aqui na globo.com, trabalho que rende bons frutos ao procurar profiles que combinem tamanho, qualidade e tempo de encoding. Ao trabalhar com profiles H.264 descobrimos uma coisa interessante: nem todos os profiles tocavam no iPhone. Não havia nenhuma regra aparente para gerar um profile “universal”, então algum tipo de teste mais “hard” deveria ser feito.

Manualmente, vc arrastava o video através do iTunes e o mesmo era aceito ou rejeitado pelo aparelho, tarefa que, se feita manualmente, é muito chata. Como automatizar isso?

Lembrei que muitos programas no mundo windows possuem uma interface COM que pode ser invocada por um vbscript ou mesmo C#. Isso me foi util uma vez quando praticamente reinventei um Selenium para integrar com uma ferramenta de testes muito ‘exotica’, dica retirada do livro .NET Test Automation Recipes: A Problem-Solution Approach. Nosso amigo google ajudou a localizar uma prova de conceito ao fazer a pesquisa “itunes vbscript”:

iCame, iPod, iScripted: Scripting iTunes

Era o que eu precisava. Talvez vcs estejam curiosos sobre vbscript ao inves de Jscript: é mais comum usar vbscript para esse fim pelo mundo afora, uma vez que COM é confundido com .com das urls pela busca do google.

Set objApp = CreateObject("iTunes.Application")
Wscript.Echo "Version: " & objApp.Version

Como podem ver, é muito simples. Existe um SDK desenvolvido pela Apple para trabalhar com o iTunes que é muito bem documentado e me ajudou muito. Bastava agora saber como adicionar os videos e capturar quando ocorre uma rejeição ou não.

Detalhes a parte, quando enfrentamos esse tipo de desafio precisamos pensar em termos de manutenção de codigo: como criar um script que tenha vida loga? Decidi usar as tecnologias mais comuns e ser o mais claro possivel (por isso vbscript, que não é tão tosco assim).

A integração com o Algoritmo Genetico foi feita usando um serviço assíncrono cuja integração era feita atraves do filesystem: bastava copiar um arquivo para um diretorio que um .bat do windows tomava conta do recado, disparando o vbscript. Foram necessarios algumas tentativas até chegar a uma estabilidade aceitável, pois acontecem coisas bem interessantes quando vc acessa uma aplicação via COM, principalmente quando um dispositivo esta ligado à USB e vc faz muitas vezes a mesma coisa. Como os serviços eram assincronos eu conseguia paralelizar parte das tarefas e, se precisasse escalar e testar em 2 ou mais aparelhos seria só desenvolver um sistema de lock apropriado (para 2 scripts não tentarem mover o mesmo arquivo).

Tirando o fato que eu tive q fazer coisas não-canônicas como usar o ping para localhost para simular um sleep (ok, considere isso como uma resposta ao select undef, undef, undef, 0.5;), foi divertido.

Esta estratégia pode ser usada em muitas coisas do mundo Windows, existem muitos exemplos pelo google afora e, se vc deseja algo mais profissional, basta usar o Visual Studio e programar em uma linguagem decente que compila e possui frameworks de teste unitários.