Existe um erro bem comum quando usamos JMockit: "Corresponding real methods not found for the following mocks".
Por um erro, meu, de tradução, imaginava que esse erro devia-se a um método da classe real não estar sendo criado na minha classe Mock, quando li com calma hoje pela manhã, percebi que é o contrário, um método implementado na minha classe Mock não existe na classe real.
Esse erro é comum de acontecer quando usamos uma classe de terceiro, normalmente empacotada num jar. No meu caso, tentava mockar a classe WebApplicationContextUtils do Spring e tive que procurar o código fonte no google pra saber a assinatura do método.
Percebi também que se você não criar o método falso para um método da classe real, ele vai invocar o método da classe real.
Mostrando postagens com marcador JMockit. Mostrar todas as postagens
Mostrando postagens com marcador JMockit. Mostrar todas as postagens
quarta-feira, 7 de maio de 2008
segunda-feira, 11 de fevereiro de 2008
Fazendo testes com Ant + JUnit + JMockit
Para fazer seus testes com o auxílio do Ant, seguem alguns passos que extraí do que já utilizamos aqui na empresa:
Primeiro Passo: crie 2 arquivos e coloque na raiz da aplicação:
build.xml
build.properties
Segundo Passo: no build.xml, crie a seguinte estrutura (ela pode ser mais simplificada):
*tire os '$' de todas as linhas
<$project name="NomeDoProjeto" basedir=".." default="integrate">
<$property file="${ant.project.name}/build.properties"/>
<$property name="project.dir" value="${ant.project.name}"/>
<$property name="src.dir" value="${project.dir}/src"/>
<$property name="build.dir" value="${project.dir}/web/WEB-INF/classes"/>
<$property name="lib.dir" value="${project.dir}/web/WEB-INF/lib"/>
<$property name="allTests.class" value="com.NomeDoProjeto.test.AllTests"/>
<$path id="project.classpath">
<$pathelement location="${build.dir}"/>
<$fileset dir="${lib.dir}">
<$include name="*.jar"/>
<$/fileset>
<$fileset dir="${tomcat.lib}">
<$include name="*-api.jar"/>
<$include name="jasper-runtime.jar"/>
<$/fileset>
<$/path>
<$taskdef name="junit" classname="org.apache.tools.ant.taskdefs.optional.junit.JUnitTask">
<$classpath refid="project.classpath"/>
<$/taskdef>
<$target name="build">
<$mkdir dir="${build.dir}"/>
<$javac debug="on" srcdir="${src.dir}" destdir="${build.dir}" failonerror="true">
<$classpath refid="project.classpath"/>
<$/javac>
<$/target>
<$target name="test" depends="build">
<$dirname file="build.xml" property="current.dir"/>
<$junit haltonfailure="true" haltonerror="true" fork="true" dir="${current.dir}">
<$jvmarg value="-javaagent:${jmockit.dir}"/>
<$classpath>
<$path refid="project.classpath"/>
<$/classpath>
<$formatter type="plain" usefile="false"/>
<$test name="${allTests.class}"/>
<$/junit>
<$/target>
<$/project>
Terceiro Passo: no build.properties, crie as variáveis( ${variavel} ) que são usadas no xml:
tomcat.lib=C:\\Arquivos de programas\\Apache Software Foundation\\Tomcat 5.5\\common\\lib
jmockit.dir=C:\\jmockit.jar
Quarto Passo: Para rodar o Ant (estou usando o Eclipse), clique com o botão direito no build.xml / Run As / Ant Build...
Na aba Targets, marque a target test e na aba Classpath, adicione o jar do JUnit.

A partir daí é só rodar.
Para o uso do JMockit adicionamos estas linhas (estão adicionadas nos exemplos acima, as linhas seguintes são somente informativas, porém se você não usar JMockit, remova-as):
No build.xml:
*sem o '$'
<$jvmarg value="-javaagent:${jmockit.dir}"/>
Adiciona o argumento na JVM.
No build.properties:
jmockit.dir=C:\\jmockit.jar
Indica onde está o jar do JMockit.
Primeiro Passo: crie 2 arquivos e coloque na raiz da aplicação:
build.xml
build.properties
Segundo Passo: no build.xml, crie a seguinte estrutura (ela pode ser mais simplificada):
*tire os '$' de todas as linhas
<$project name="NomeDoProjeto" basedir=".." default="integrate">
<$property file="${ant.project.name}/build.properties"/>
<$property name="project.dir" value="${ant.project.name}"/>
<$property name="src.dir" value="${project.dir}/src"/>
<$property name="build.dir" value="${project.dir}/web/WEB-INF/classes"/>
<$property name="lib.dir" value="${project.dir}/web/WEB-INF/lib"/>
<$property name="allTests.class" value="com.NomeDoProjeto.test.AllTests"/>
<$path id="project.classpath">
<$pathelement location="${build.dir}"/>
<$fileset dir="${lib.dir}">
<$include name="*.jar"/>
<$/fileset>
<$fileset dir="${tomcat.lib}">
<$include name="*-api.jar"/>
<$include name="jasper-runtime.jar"/>
<$/fileset>
<$/path>
<$taskdef name="junit" classname="org.apache.tools.ant.taskdefs.optional.junit.JUnitTask">
<$classpath refid="project.classpath"/>
<$/taskdef>
<$target name="build">
<$mkdir dir="${build.dir}"/>
<$javac debug="on" srcdir="${src.dir}" destdir="${build.dir}" failonerror="true">
<$classpath refid="project.classpath"/>
<$/javac>
<$/target>
<$target name="test" depends="build">
<$dirname file="build.xml" property="current.dir"/>
<$junit haltonfailure="true" haltonerror="true" fork="true" dir="${current.dir}">
<$jvmarg value="-javaagent:${jmockit.dir}"/>
<$classpath>
<$path refid="project.classpath"/>
<$/classpath>
<$formatter type="plain" usefile="false"/>
<$test name="${allTests.class}"/>
<$/junit>
<$/target>
<$/project>
Terceiro Passo: no build.properties, crie as variáveis( ${variavel} ) que são usadas no xml:
tomcat.lib=C:\\Arquivos de programas\\Apache Software Foundation\\Tomcat 5.5\\common\\lib
jmockit.dir=C:\\jmockit.jar
Quarto Passo: Para rodar o Ant (estou usando o Eclipse), clique com o botão direito no build.xml / Run As / Ant Build...
Na aba Targets, marque a target test e na aba Classpath, adicione o jar do JUnit.
A partir daí é só rodar.
Para o uso do JMockit adicionamos estas linhas (estão adicionadas nos exemplos acima, as linhas seguintes são somente informativas, porém se você não usar JMockit, remova-as):
No build.xml:
*sem o '$'
<$jvmarg value="-javaagent:${jmockit.dir}"/>
No build.properties:
jmockit.dir=C:\\jmockit.jar
Indica onde está o jar do JMockit.
Problema com JMockit
O JMockit foi comentado no post Mockando um Método Estático.
Bem, em algumas maquinas aqui da empresa, estava acontecendo o seguinte erro:
java.lang.VerifyError: (class: junit/framework/TestCase, method: runTest signature: ()V) Illegal constant pool index
at java.lang.Class.getDeclaredMethods0(Native Method)
at java.lang.Class.privateGetDeclaredMethods(Class.java:2365)
at java.lang.Class.getMethod0(Class.java:2611)
at java.lang.Class.getMethod(Class.java:1579)at org.eclipse.jdt.internal.junit.runner.junit3.JUnit3TestLoader.
getTest(JUnit3TestLoader.java:99)at org.eclipse.jdt.internal.junit.runner.junit3.JUnit3TestLoader.
loadTests(JUnit3TestLoader.java:59)at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.
runTests(RemoteTestRunner.java:445)at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.
runTests(RemoteTestRunner.java:673)at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.
run(RemoteTestRunner.java:386)at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.
main(RemoteTestRunner.java:196)
O interessante esta no trecho "em algumas maquinas", se o jar do JMockit e o método onde foi usado são os mesmos, por que somente em algumas maquinas aconteceu esse erro, e não em todas?
A verdade é que o erro não tem nada haver com JMockit, mas como faz parte do processo de fazer o JMockit funcionar, vou postar a minha solução aqui:
Li em vários lugares que o problema era causado pela JVM, que não suportava o parâmetro (figura abaixo). Onde li, dizia que o motivo era a quantidade de parâmetros passados pra JVM, e que era um problema da VM do Java 5. Não me aprofundei no assunto e nem pretendo.

O Runtime JRE, estava apontando para o diretório de uma JRE instalada, então apontei para o diretório da JDK e pronto, funcionou:

Caso este procedimento não seja suficiente para fazer com que seus testes funcionem, o problema pode ser da versão da sua JVM (a testada foi 1.5.0_08), instale outra e refaça o procedimento.
Bem, em algumas maquinas aqui da empresa, estava acontecendo o seguinte erro:
java.lang.VerifyError: (class: junit/framework/TestCase, method: runTest signature: ()V) Illegal constant pool index
at java.lang.Class.getDeclaredMethods0(Native Method)
at java.lang.Class.privateGetDeclaredMethods(Class.java:2365)
at java.lang.Class.getMethod0(Class.java:2611)
at java.lang.Class.getMethod(Class.java:1579)at org.eclipse.jdt.internal.junit.runner.junit3.JUnit3TestLoader.
getTest(JUnit3TestLoader.java:99)at org.eclipse.jdt.internal.junit.runner.junit3.JUnit3TestLoader.
loadTests(JUnit3TestLoader.java:59)at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.
runTests(RemoteTestRunner.java:445)at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.
runTests(RemoteTestRunner.java:673)at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.
run(RemoteTestRunner.java:386)at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.
main(RemoteTestRunner.java:196)
O interessante esta no trecho "em algumas maquinas", se o jar do JMockit e o método onde foi usado são os mesmos, por que somente em algumas maquinas aconteceu esse erro, e não em todas?
A verdade é que o erro não tem nada haver com JMockit, mas como faz parte do processo de fazer o JMockit funcionar, vou postar a minha solução aqui:
Li em vários lugares que o problema era causado pela JVM, que não suportava o parâmetro (figura abaixo). Onde li, dizia que o motivo era a quantidade de parâmetros passados pra JVM, e que era um problema da VM do Java 5. Não me aprofundei no assunto e nem pretendo.
O Runtime JRE, estava apontando para o diretório de uma JRE instalada, então apontei para o diretório da JDK e pronto, funcionou:
Caso este procedimento não seja suficiente para fazer com que seus testes funcionem, o problema pode ser da versão da sua JVM (a testada foi 1.5.0_08), instale outra e refaça o procedimento.
sexta-feira, 14 de dezembro de 2007
JMockit - Mockando um Método Estático
É com grande felicidade que consegui, nesta manhã de sexta, mockar um método estático, p&#@ que p@$%&, sensacional.
O nome do cara é JMockit
Bem, o meu exemplo é bem simples:
Criei uma classe que tem somente um método estático, é esta classe que quero mockar:
Redefino os métodos da classe real pelos da classe mock:
E para voltar "ao normal":
No eclipse é só fazer isso, na hora de rodar o teste:

ou isso, para rodar com test suite ou qualquer outro lugar:
O nome do cara é JMockit
Bem, o meu exemplo é bem simples:
Criei uma classe que tem somente um método estático, é esta classe que quero mockar:
0: public class ClasseUtil {Então, uma classe que utiliza este método:
1: public static int metodoEstatico()
2: {
3: return 1;
4: }
5: }
0: public class ClasseFuncionalidade {Por fim, a classe de teste:
1: public static int metodoLocal()
2: {
3: return ClasseUtil.metodoEstatico();
4: }
5: }
0: public class ClasseFuncionalidadeTeste{Perceba que criei uma outra classe (inner class) chamada MockClasseUtil, com um método (metodoEstatico) de mesma assinatura do método da classe ClasseUtil, porém o retorno é diferente (No original é 1 e no falso é 0).
1:
2: public static class MockClasseUtil{
3: public static int metodoEstatico()
4: {
5: return 0;
6: }
7: }
8:
9: @Before
10: public void prepare(){
11: Mockit.redefineMethods(
12: ClasseUtil.class,
13: MockClasseUtil.class);
14: }
15:
16: @After
17: public void finalize(){
18: Mockit.restoreAllOriginalDefinitions();
19: }
20:
21: @Test
22: public void metodoLocal(){
23: assertEquals(0, ClasseFuncionalidade.
24: metodoLocal());
25: }
26: }
Redefino os métodos da classe real pelos da classe mock:
0: @BeforeSe fosse no JUnit3, poderia usar o método setUp para invocar o redefineMethods.
1: public void prepare(){
2: Mockit.redefineMethods(
3: ClasseUtil.class,
4: MockClasseUtil.class);
5: }
E para voltar "ao normal":
0: @AfterA única dificuldade foi "ver" que o comando "-javaagent:jmockit.jar" deve ser passado como parâmetro para a JVM:
1: public void finalize(){
2: Mockit.restoreAllOriginalDefinitions();
3: }
No eclipse é só fazer isso, na hora de rodar o teste:
ou isso, para rodar com test suite ou qualquer outro lugar:
Assinar:
Postagens (Atom)