JUnit4 测试类是否需要公共无参数构造函数?

发布于 2024-08-04 19:59:09 字数 3535 浏览 3 评论 0原文

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

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)

我在类中没有 public no arg 构造函数,但这真的有必要吗?

这是我的 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>

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

I have a test class, written in JUnit4 syntax, that can be run in eclipse with the "run as junit test" option without failing. When I run the same test via an ant target I get this error:

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)

I have no public no arg constructor in the class, but is this really necessary?

This is my ant target

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

The test class have no constructors, but it has an inner class with default modifier. It also have an anonymouse inner class. Both inner classes gives the "Test class should have public zero-argument constructor error". I am using Ant version 1.7.1 and JUnit 4.7

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

夜深人未静 2024-08-11 19:59:09

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

I believe you need a no-args constructor, but if you don't declare any constructors Java will create a synthetic one for you. Are you sure the ant-task is not picking up another class; one that just happens to follow the naming convention you've set (*Test or Test*)?

落花随流水 2024-08-11 19:59:09

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

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

You must have a default constructor for the test case. Otherwise, the runner doesn't know how to instantiate the class. Looks like you have a constructor with args. Java doesn't create default constructor if you already have a constructor.

Generally, you should avoid constructors in test cases. If you want do initialization, write a init method and annotate it with @BeforeClass. The benefit is that the stack trace will be much cleaner if you have any errors. As you can see, the constructor's stack trace is really confusing for most people.

唔猫 2024-08-11 19:59:09

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

查看 JUnit 4.3.1、4.5 和 4.7 的源代码(尤其是测试运行程序的源代码)会发现测试类必须具有公共的零参数构造函数。请注意,JUnit v4.7 中的默认运行器是 BlockJUnit4ClassRunner。您会注意到 javadoc(多可惜!)包含构成格式良好的测试类应遵循的规则 - 公共零参数构造函数就是其中之一。

Eclipse uses a different implementation to execute JUnit4 test cases - it has its own test runner. This happens to be different from the one used by the Ant - the default one available in the JUnit distribution, and is the reason for the discrepancy noted in the execution behavior of the environments in Ant and Eclipse.

Taking a look at the source code of JUnit 4.3.1, 4.5 and 4.7 (especially that of the testrunners) reveals that test classes must have a public zero-arg constructor. Do note that the default runner in JUnit v4.7 is BlockJUnit4ClassRunner. You'll notice that the javadocs (what a pity!) contain the rules to be followed on what constitutes a well formed test class - a public zero-argument constructor is one of them.

猫九 2024-08-11 19:59:09

感谢大家的宝贵时间和您的回答。
我现在已经找到了解决方案。以前我认为 ant 目标的批量测试部分的输入应该是 .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:如何避免测试实用程序类中的“无可运行方法”

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

Thank you all for your time and your answers.
I have now found a solution. Previously I thought the input for the batchtest part of my ant target should be .class files but it is also possible to use .java files.

That solved the problem. Now it no longer complains about inner classes missing public constructors.

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

My only problem now is, that I have to filter out the test classes without tests, in order to avoid a "No runnable methods"-error. That is, the helper and util classes.

There must be a more elegant solution than mine. One solution could be a naming convention as suggested [JUnit: how to avoid "no runnable methods" in test utils classes.

The helper classes does not contain the @Test annotaion. It must be possible to utilize this in some way...

爱她像谁 2024-08-11 19:59:09

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

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

Instances of your test classes need to be made somehow. You can create a no-arg test which adds test instances created in some other way, which can be useful for parameterising tests (or was in JUnit 3, anyway).

But why would you suppress the synthetic no-arg constructor?

最好是你 2024-08-11 19:59:09

使用无参数构造函数可以将测试类聚合到套件中:

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

Having a no-arg constructor allows test classes to be aggregated into suites:

 TestSuite suite = new TestSuite();
 suite.add(TestClass.class);
 ...
热情消退 2024-08-11 19:59:09

对于老版本的junit,如果你的内部类中有“Test”这个词,就会出现这个问题。

我们在实现子类测试模式时遇到了这个问题,命名子类,例如 FooForTest。通过重命名为FooSubclass,问题就解决了。

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

希望有帮助!

For older versions of junit, if you have the word "Test" in your inner class, this problem will occur.

We ran into this problem while implementing the subclass-for-test pattern, naming the subclass, e.g., FooForTest. By renaming to FooSubclass, the problem was solved.

See the above comment from @Vineet Reynolds for more detail about affected junit versions, and why this happens for ant but not eclipse.

Hope that helps!

没企图 2024-08-11 19:59:09

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

Non-static inner classes have a hidden constructor that takes the outer class as argument. If your inner classes dont share state with the outer classes, just make them static.

顾挽 2024-08-11 19:59:09

可能是因为您使用的是 Enclosure.class,那么封闭的类必须是 static

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

}

Could be because you are using Enclosed.class, then the enclosed classes has to be static

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

}

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文