Требует ли JUnit4 testclasses открытого конструктора no arg?

у меня есть тестовый класс, написанный в синтаксисе JUnit4, который можно запустить в eclipse с опцией "run as junit test" без сбоев. Когда я запускаю тот же тест через цель 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)

у меня нет публичного конструктора 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 ответов


Я считаю, что вам нужен конструктор no-args, но если вы не объявите никаких конструкторов, Java создаст для вас синтетический. Вы уверены, что ant-task не собирает другой класс; тот, который просто следует соглашению об именах, которое вы установили (*Test или Test*)?


У вас должен быть конструктор по умолчанию для тестового набора. В противном случае бегун не знает, как создать экземпляр класса. Похоже, у вас есть конструктор с аргументами. Java не создает конструктор по умолчанию, если у вас уже есть конструктор.

Как правило, в тестовых случаях следует избегать конструкторов. Если вы хотите сделать инициализацию, напишите метод init и аннотируйте его с помощью @BeforeClass. Преимущество заключается в том, что трассировка стека будет гораздо чище, если у вас есть какие-либо ошибки. Как и ты можно видеть, что трассировка стека конструктора действительно сбивает с толку для большинства людей.


Eclipse использует различную реализацию для выполнения JUnit4 тесты - это своя тестов. Это отличается от того, который используется Ant - по умолчанию, доступный в дистрибутиве JUnit, и является причиной расхождения, отмеченного в поведении выполнения сред в Ant и Eclipse.

взглянув на исходный код JUnit 4.3.1, 4.5 и 4.7 (особенно тестраннеров) показывает, что тестовые классы должны иметь открытый ноль аргументов конструктора. Обратите внимание, что бегун по умолчанию в JUnit v4.7 is BlockJUnit4ClassRunner. Вы заметите, что javadocs (какая жалость!) содержат правила, которым следует следовать в отношении того, что представляет собой хорошо сформированный тестовый класс - одним из них является открытый конструктор нулевого аргумента.


спасибо всем за ваше время и ответы. Теперь я нашел решение. Раньше я думал, что вход для 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>

моя единственная проблема теперь заключается в том, что я должен отфильтровать тестовые классы без тестов, чтобы избежать "no runnable методы"-ошибка. То есть классы helper и util.

должно быть более элегантное решение, чем мое. Одним из решений может быть соглашение об именах, как предложено [JUnit: как избежать "не запускаемых методов" в тестовых классах utils.

вспомогательные классы не содержат аннотации @Test. Это должно быть возможно каким-то образом использовать...


экземпляры ваших тестовых классов должны быть сделаны как-то. Вы можете создать тест no-arg, который добавляет тестовые экземпляры, созданные каким-то другим способом, который может быть полезен для параметризации тестов (или был в JUnit 3, так или иначе).

но почему вы подавляете синтетический конструктор no-arg?


наличие конструктора no-arg позволяет агрегировать тестовые классы в наборы:

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

для более старых версий junit, если у вас есть слово "тест" во внутреннем классе, эта проблема возникнет.

мы столкнулись с этой проблемой при реализации шаблона подкласса для тестирования, называя подкласс, например, FooForTest. Переименованием в FooSubclass проблема была решена.

см. выше комментарий от @Vineet Reynolds для более подробной информации о затронутых версиях junit и почему это происходит для ant, но не eclipse.

надеюсь, что это поможет!


нестатические внутренние классы имеют скрытый конструктор, который принимает внешний класс в качестве аргумента. Если ваши внутренние классы не разделяют состояние с внешними классами, просто сделайте их static.


может быть потому, что вы используете закрытый.класс, тогда вложенные классы должны быть 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(){
}
}

}