JUnit4测试类是否需要public no arg构造函数?

时间:2009-09-20 17:20:24

标签: java ant junit

我有一个用JUnit4语法编写的测试类,可以使用“run as junit test”选项在eclipse中运行而不会失败。当我通过蚂蚁目标运行相同的测试时,我收到此错误:

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)

我在课堂上没有公开的arg构造函数,但这真的有必要吗?

这是我的蚂蚁目标

<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>

测试类没有构造函数,但它有一个带有默认修饰符的内部类。它也有一个匿名内部类。两个内部类都给出了“测试类应该具有公共零参数构造函数错误”。我正在使用Ant版本1.7.1和JUnit 4.7

9 个答案:

答案 0 :(得分:8)

我相信你需要一个no-args构造函数,但如果你没有声明任何构造函数,Java将为你创建一个合成构造函数。你确定蚂蚁任务没有进入另一个班级;恰好遵循您设置的命名约定(*TestTest*)?

答案 1 :(得分:5)

您必须拥有测试用例的默认构造函数。否则,跑步者不知道如何实例化该类。看起来你有一个带args的构造函数。如果您已经有一个构造函数,Java不会创建默认构造函数。

通常,您应该避免在测试用例中使用构造函数。如果要进行初始化,请编写init方法并使用@BeforeClass进行注释。好处是,如果您有任何错误,堆栈跟踪将更加清晰。正如您所看到的,构造函数的堆栈跟踪对于大多数人来说确实令人困惑。

答案 2 :(得分:5)

Eclipse使用不同的实现来执行JUnit4测试用例 - 它有自己的测试运行器。这恰好与Ant使用的不同 - 在JUnit发行版中可用的默认版本,并且是Ant和Eclipse中环境执行行为中出现差异的原因。

看一下JUnit 4.3.1,4.5和4.7的源代码(特别是testrunners的源代码),我们发现测试类必须有一个公共的零参数构造函数。请注意,JUnit v4.7中的默认运行程序为BlockJUnit4ClassRunner。您会注意到javadocs(真可惜!)包含了构成格式良好的测试类的规则 - 公共零参数构造函数就是其中之一。

答案 3 :(得分:3)

谢谢大家的时间和答案。 我现在找到了解决方案。以前我认为我的ant目标的batchtest部分的输入应该是.class文件,但也可以使用.java文件。

解决了这个问题。现在它不再抱怨缺少公共构造函数的内部类。

<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>

我现在唯一的问题是,我必须在没有测试的情况下过滤掉测试类,以避免“没有可运行的方法” - 错误。也就是helper和util类。

必须有比我更优雅的解决方案。一种解决方案可以是建议[JUnit: how to avoid "no runnable methods" in test utils classes

的命名约定

帮助程序类不包含@Test注释。必须有可能以某种方式利用它......

答案 4 :(得分:1)

您的测试类的实例需要以某种方式进行。您可以创建一个无参数测试,添加以其他方式创建的测试实例,这对于参数化测试非常有用(或者无论如何都在JUnit 3中)。

但是为什么要压制合成的无参数构造函数?

答案 5 :(得分:1)

使用no-arg构造函数可以将测试类聚合到套件中:

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

答案 6 :(得分:1)

对于旧版本的junit,如果您的内部类中有单词“Test”,则会出现此问题。

我们在实现子类for-test模式时遇到了这个问题,命名了子类,例如FooForTest。通过重命名为FooSubclass,问题得以解决。

请参阅@Vineet Reynolds的上述评论,了解有关受影响的junit版本的详细信息,以及为什么会出现这种情况,而不是eclipse。

希望有所帮助!

答案 7 :(得分:0)

非静态内部类有一个隐藏的构造函数,它将外部类作为参数。如果你的内部类不与外部类共享状态,只需将它们设为static

答案 8 :(得分:0)

可能是因为您使用的是Enclosed.class,所以封闭的类必须是静态

@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(){
}
}

}