Qual é a melhor estrutura para criar objetos simulados em Java? Por quê? Quais são os prós e os contras de cada estrutura?
Qual é a melhor estrutura para criar objetos simulados em Java? Por quê? Quais são os prós e os contras de cada estrutura?
Respostas:
Eu tive um bom sucesso usando o Mockito .
Quando tentei aprender sobre o JMock e o EasyMock, achei a curva de aprendizado um pouco íngreme (embora talvez seja apenas eu).
Eu gosto do Mockito por causa de sua sintaxe simples e limpa que eu pude entender rapidamente. A sintaxe mínima foi projetada para suportar muito bem os casos comuns, embora nas poucas vezes em que precisei fazer algo mais complicado, achei que o que queria era suportado e fácil de entender.
Aqui está um exemplo (resumido) da página inicial do Mockito:
import static org.mockito.Mockito.*;
List mockedList = mock(List.class);
mockedList.clear();
verify(mockedList).clear();
Não fica muito mais simples que isso.
A única grande desvantagem em que consigo pensar é que ele não zombará de métodos estáticos.
Eu sou o criador do PowerMock, então, obviamente, devo recomendar isso! :-)
O PowerMock estende o EasyMock e o Mockito com a capacidade de zombar de métodos estáticos , finais e até particulares. O suporte ao EasyMock está completo, mas o plug-in Mockito precisa de mais trabalho. Também estamos planejando adicionar suporte ao JMock.
O PowerMock não se destina a substituir outras estruturas, mas pode ser usado em situações complicadas em que outras estruturas não permitem zombarias. O PowerMock também contém outros recursos úteis, como suprimir inicializadores e construtores estáticos .
O site do projeto JMockit contém muitas informações comparativas para os kits de ferramentas de simulação atuais.
Em particular, confira a matriz de comparação de recursos , que abrange EasyMock, jMock, Mockito, Unitils Mock, PowerMock e, é claro, JMockit. Tento mantê-lo preciso e atualizado, o máximo possível.
Eu tenho tido sucesso com o JMockit .
É bem novo e, portanto, um pouco cru e sub-documentado. Ele usa o ASM para redefinir dinamicamente o bytecode da classe, para que possa zombar de todos os métodos, incluindo estático, privado, construtores e inicializadores estáticos. Por exemplo:
import mockit.Mockit;
...
Mockit.redefineMethods(MyClassWithStaticInit.class,
MyReplacementClass.class);
...
class MyReplacementClass {
public void $init() {...} // replace default constructor
public static void $clinit{...} // replace static initializer
public static void myStatic{...} // replace static method
// etc...
}
Possui uma interface de expectativas, permitindo também cenários de gravação / reprodução:
import mockit.Expectations;
import org.testng.annotations.Test;
public class ExpecationsTest {
private MyClass obj;
@Test
public void testFoo() {
new Expectations(true) {
MyClass c;
{
obj = c;
invokeReturning(c.getFoo("foo", false), "bas");
}
};
assert "bas".equals(obj.getFoo("foo", false));
Expectations.assertSatisfied();
}
public static class MyClass {
public String getFoo(String str, boolean bool) {
if (bool) {
return "foo";
} else {
return "bar";
}
}
}
}
A desvantagem é que ele requer Java 5/6.
Você também pode dar uma olhada nos testes usando o Groovy. No Groovy, você pode facilmente zombar de interfaces Java usando o operador 'as':
def request = [isUserInRole: { roleName -> roleName == "testRole"}] as HttpServletRequest
Além dessa funcionalidade básica, o Groovy oferece muito mais na frente de zombaria, incluindo os poderosos MockFor
e as StubFor
classes.
Comecei a usar zombarias com o EasyMock . Fácil de entender, mas a etapa de repetição foi meio irritante. O Mockito remove isso, também possui uma sintaxe mais limpa, pois parece que a legibilidade era um dos seus principais objetivos. Não posso enfatizar o suficiente o quanto isso é importante, já que a maioria dos desenvolvedores gasta seu tempo lendo e mantendo o código existente, não o criando.
Outra coisa interessante é que interfaces e classes de implementação são tratadas da mesma maneira, ao contrário do EasyMock, onde você ainda precisa se lembrar (e verificar) para usar uma Extensão de Classe EasyMock.
Dei uma olhada rápida no JMockit recentemente e, embora a lista de recursos seja bastante abrangente, acho que o preço disso é legibilidade do código resultante e é preciso escrever mais.
Para mim, Mockito atinge o ponto ideal, sendo fácil de escrever e ler, e lidando com a maioria das situações que a maioria dos códigos exige. Usar o Mockito com o PowerMock seria minha escolha.
Uma coisa a considerar é que a ferramenta que você escolheria se estivesse desenvolvendo sozinha ou em uma pequena equipe unida pode não ser a melhor opção para uma grande empresa com desenvolvedores de diferentes níveis de habilidade. Legibilidade, facilidade de uso e simplicidade precisariam de mais consideração neste último caso. Não faz sentido obter a estrutura de zombaria definitiva se muitas pessoas acabam não a usando ou não mantendo os testes.
Estamos usando muito o EasyMock e o EasyMock Class Extension no trabalho e estamos muito felizes com isso. Basicamente, fornece tudo o que você precisa. Dê uma olhada na documentação, há um exemplo muito bom que mostra todos os recursos do EasyMock.
Eu usei o JMock cedo. Eu tentei o Mockito no meu último projeto e gostei. Mais conciso, mais limpo. O PowerMock cobre todas as necessidades ausentes no Mockito, como zombar de um código estático, zombar de uma criação de instância, zombar de classes e métodos finais. Então, eu tenho tudo o que preciso para realizar meu trabalho.
Eu gosto do JMock porque você é capaz de estabelecer expectativas. Isso é totalmente diferente de verificar se um método foi chamado encontrado em algumas bibliotecas simuladas. Usando o JMock, você pode escrever expectativas muito sofisticadas. Veja o jmock cheat- sheat .
Sim, o Mockito é uma ótima estrutura. Eu o uso junto com o hamcrest e o Google guice para configurar meus testes.
A melhor solução para zombar é fazer com que a máquina faça todo o trabalho com testes automatizados baseados em especificações. Para Java, consulte ScalaCheck e a estrutura Reductio incluída na biblioteca Java Funcional . Com estruturas de teste automatizadas baseadas em especificação, você fornece uma especificação do método em teste (uma propriedade sobre isso que deve ser verdadeira) e a estrutura gera testes e objetos simulados automaticamente.
Por exemplo, a propriedade a seguir testa o método Math.sqrt para verificar se a raiz quadrada de qualquer número positivo n ao quadrado é igual a n.
val propSqrt = forAll { (n: Int) => (n >= 0) ==> scala.Math.sqrt(n*n) == n }
Quando você liga propSqrt.check()
, o ScalaCheck gera centenas de números inteiros e verifica sua propriedade para cada um, também assegurando automaticamente que os casos extremos sejam bem cobertos.
Embora o ScalaCheck seja escrito em Scala e exija o Scala Compiler, é fácil testar o código Java com ele. A estrutura Reductio em Java Funcional é uma implementação Java pura dos mesmos conceitos.
O Mockito também oferece a opção de métodos de stubbing, correspondência de argumentos (como anyInt () e anyString ()), verificação do número de invocações (times (3), atLeastOnce (), never ()) e muito mais .
Também descobri que o Mockito é simples e limpo .
Uma coisa que eu não gosto no Mockito é que você não pode stub métodos estáticos .
Para algo um pouco diferente, você pode usar o JRuby e o Mocha, que são combinados no JtestR para escrever testes para o seu código Java no Ruby expressivo e sucinto. Existem alguns exemplos úteis de zombaria com o JtestR aqui . Uma vantagem dessa abordagem é que zombar de classes concretas é muito direto.
Comecei a usar zombarias através do JMock, mas eventualmente fiz a transição para usar o EasyMock. O EasyMock era exatamente isso - mais fácil - e fornecia uma sintaxe que parecia mais natural. Eu não mudei desde então.