2009-09-20 10 views
11

Tengo una clase de prueba, escrita en sintaxis JUnit4, que se puede ejecutar en eclipse con la opción "ejecutar como prueba junit" sin fallar. Cuando ejecuto la misma prueba a través de una tarea ant consigo este error:¿Las clases de prueba JUnit4 requieren un constructor público no arg?

java.lang.Exception: Test class should have public zero-argument constructor 
at org.junit.internal.runners.MethodValidator.validateNoArgConstructor(MethodValidator.java:54) 
at org.junit.internal.runners.MethodValidator.validateAllMethods(MethodValidator.java:39) 
at org.junit.internal.runners.TestClassRunner.validate(TestClassRunner.java:33) 
at org.junit.internal.runners.TestClassRunner.<init>(TestClassRunner.java:27) 
at org.junit.internal.runners.TestClassRunner.<init>(TestClassRunner.java:20) 
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) 
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39) 
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27) 
at java.lang.reflect.Constructor.newInstance(Constructor.java:513) 
at org.junit.internal.requests.ClassRequest.getRunner(ClassRequest.java:26) 
at junit.framework.JUnit4TestAdapter.<init>(JUnit4TestAdapter.java:24) 
at junit.framework.JUnit4TestAdapter.<init>(JUnit4TestAdapter.java:17) 
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) 
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39) 
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27) 
at java.lang.reflect.Constructor.newInstance(Constructor.java:513) 
at org.apache.tools.ant.taskdefs.optional.junit.JUnitTestRunner.run(JUnitTestRunner.java:386) 
at org.apache.tools.ant.taskdefs.optional.junit.JUnitTestRunner.launch(JUnitTestRunner.java:911) 
at org.apache.tools.ant.taskdefs.optional.junit.JUnitTestRunner.main(JUnitTestRunner.java:768) 
Caused by: java.lang.NoSuchMethodException: dk.gensam.gaia.business.bonusregulering.TestBonusregulerAftale$Test1Reader.<init>() 
at java.lang.Class.getConstructor0(Class.java:2706) 
at java.lang.Class.getConstructor(Class.java:1657) 
at org.junit.internal.runners.MethodValidator.validateNoArgConstructor(MethodValidator.java:52) 

que no tengo ningún constructor público arg en la clase, pero ¿es realmente necesario?

Esta es mi tarea ant

<target name="junit" description="Execute unit tests" depends="compile, jar-test"> 
     <delete dir="tmp/rawtestoutput"/> 
     <delete dir="test-reports"/> 
     <mkdir dir="tmp/rawtestoutput"/> 
     <junit printsummary="true" failureproperty="junit.failure" fork="true"> 
      <classpath refid="class.path.test"/> 
      <classpath refid="class.path.model"/> 
      <classpath refid="class.path.gui"/> 
      <classpath refid="class.path.jfreereport"/> 
      <classpath path="tmp/${test.jar}"></classpath> 
      <batchtest todir="tmp/rawtestoutput"> 
      <fileset dir="${build}/test"> 
       <include name="**/*Test.class" /> 
       <include name="**/Test*.class" /> 
      </fileset> 
      </batchtest> 
     </junit> 
     <junitreport todir="tmp"> 
      <fileset dir="tmp/rawtestoutput"/> 
      <report todir="test-reports"/> 
     </junitreport> 
     <fail if="junit. 
failure" message="Unit test(s) failed. See reports!"/> 
    </target> 

La clase de prueba no tienen constructores, pero tiene una clase interna con el modificador por defecto. También tiene una clase interna anonymouse. Ambas clases internas dan la "Clase de prueba debe tener un error de constructor público de cero argumentos". Estoy usando Ant versión 1.7.1 y JUnit 4.7

Respuesta

3

Gracias a todos por su tiempo y sus respuestas. Ahora he encontrado una solución. Anteriormente, pensé que la entrada para la parte por lotes de mi objetivo ant debe ser archivos .class, pero también es posible utilizar archivos .java.

Eso resolvió el problema. Ahora ya no se queja de las clases internas que faltan constructores públicos.

<target name="junit" description="Execute unit tests"> 
<delete dir="tmp/rawtestoutput"/> 
<delete dir="test-reports"/> 
    <mkdir dir="tmp/rawtestoutput"/>  
    <junit printsummary="on" failureproperty="junit.failure" fork="true"> 
     <jvmarg value="-Duser=TBA -Dpassword=ibber11"/> 
     <classpath refid="class.path.test"/> 
     <classpath refid="class.path.model"/> 
     <classpath refid="class.path.gui"/> 
     <classpath refid="class.path.jfreereport"/> 
    <classpath path="tmp/${test.jar}"/> 
     <batchtest todir="tmp/rawtestoutput"> 
     <fileset dir="src/test"> 
      <include name="**/*.java"/> 
     <exclude name="**/SessionHelper.java"/> 
     <exclude name="**/TestHelper.java"/> 
     </fileset> 
     </batchtest> 
    <sysproperty key="user" value="tba"/> 
    <sysproperty key="password" value="ibber11"/> 
    </junit> 
    <junitreport todir="tmp"> 
     <fileset dir="tmp/rawtestoutput"/> 
     <report todir="test-reports"/> 
    </junitreport> 
    <fail if="junit.failure" message="Unit test(s) failed. See reports!"/> 
</target> 

Mi único problema ahora es, que tengo que filtrar las clases de prueba y sin pruebas, con el fin de evitar una -error "No hay métodos ejecutables". Es decir, las clases auxiliar y util.

Tiene que haber una solución más elegante que la mía. Una solución podría ser una convención de nomenclatura según lo sugerido [JUnit: how to avoid "no runnable methods" in test utils classes.

Las clases de ayuda no contiene el annotaion @test. Debe ser posible utilizar esto de alguna manera ...

+0

Intentar excluir **/* Helper.java. –

1

Las instancias de sus clases de prueba deben hacerse de alguna manera. Puede crear una prueba sin argumentos que agregue instancias de prueba creadas de alguna otra manera, lo que puede ser útil para parametrizar las pruebas (o estaba en JUnit 3, de todos modos).

¿Pero por qué suprimiría el constructor sintético no-arg?

1

Habiendo un constructor sin argumentos permite que las clases de prueba para ser agregado en suites:

TestSuite suite = new TestSuite(); 
suite.add(TestClass.class); 
... 
8

que cree que necesita un constructor sin argumentos, pero si no se declara ningún constructor de Java creará un sintética uno para ti. ¿Estás seguro de que la ant-tarea no está recogiendo otra clase? uno que simplemente sigue la convención de nomenclatura que ha establecido (*Test o Test*)?

5

Debe tener un constructor predeterminado para el caso de prueba. De lo contrario, el corredor no sabe cómo crear una instancia de la clase. Parece que tienes un constructor con args. Java no crea un constructor predeterminado si ya tiene un constructor.

Generalmente, debe evitar constructores en casos de prueba. Si desea hacer la inicialización, escriba un método init y anótelo con @BeforeClass. El beneficio es que el seguimiento de la pila será mucho más limpio si tiene algún error. Como puede ver, el seguimiento de la pila del constructor es realmente confuso para la mayoría de las personas.

5

Eclipse utiliza una implementación diferente para ejecutar casos de prueba JUnit4: tiene su propio corredor de prueba. Esto pasa a ser diferente del usado por la Ant, el predeterminado disponible en la distribución JUnit, y es el motivo de la discrepancia observada en el comportamiento de ejecución de los entornos en Ant y Eclipse.

Echar un vistazo al código fuente de JUnit 4.3.1, 4.5 y 4.7 (especialmente el de los testrunners) revela que las clases de prueba deben tener un constructor público de cero arg. Tenga en cuenta que el corredor predeterminado en JUnit v4.7 es BlockJUnit4ClassRunner. Notarás que los javadocs (¡qué lástima!) Contienen las reglas que se deben seguir en lo que constituye una clase de prueba bien formada: uno de ellos es un constructor público de argumentos cero.

+0

Estaba pensando lo mismo que tú. Que tiene algo que ver con junit3 vs junit4, pero por lo que puedo ver en la stacktrace es en realidad un JUnit4TestAdapter que está involucrado. –

+0

Bueno, eche un vistazo a las fuentes de Ant 1.7.1. En JUnitTestRunner.java (línea 386 que aparece en el seguimiento de la pila) se crea una instancia de TestSuite, solo si se cumplen las condiciones previas. –

+0

Vaya, mal, la línea 396 crea el TestSuite mientras que el 386 crea el JUnit4TestAdapter. –

0

clases internas estáticas no tienen un constructor oculto que lleva la clase externa como argumento. Si tus clases internas no comparten el estado con las clases externas, solo hazlas static.

1

Para versiones anteriores de JUnit, si usted tiene la palabra "prueba" en su clase interna, se producirá este problema.

nos encontramos con este problema al aplicar el patrón subclase-de-prueba, nombrando a la subclase, por ejemplo, FooForTest. Al cambiar el nombre a FooSubclass, el problema se solucionó.

Ver el comentario anterior de @Vineet Reynolds para obtener más detalles acerca de las versiones junit afectadas, y por qué esto sucede por la hormiga, pero no eclipse.

Espero que ayude!

0

podría deberse a que está utilizando Enclosed.class, entonces las clases tiene que ser cerrados estática

@RunWith(Enclosed.class) 
public class MyClassThatCointaintTestClasses { 
    public static class Class1Test { 
@Test 
public void test1(){ 
} 
@Test 
public void test2(){ 
} 
} 

public static class Class2Test { 
@Test 
public void test21(){ 
} 
@Test 
public void test22(){ 
} 
} 

}

Cuestiones relacionadas