Для тестовых классов JUnit4 требуется публичный конструктор 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 в классе, но действительно ли это необходимо?

Это мой 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>

В тестовом классе нет конструкторов, но он имеет внутренний класс с модификатором по умолчанию. Он также имеет внутренний класс анонимных. Оба внутренних класса дают "Тест-класс должен иметь публичную ошибку конструктора с нулевым аргументом". Я использую ant версию 1.7.1 и JUnit 4.7

Ответ 1

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

Моя единственная проблема сейчас в том, что я должен отфильтровать тестовые классы без тестов, чтобы избежать "Без запускаемых методов" -error. То есть, вспомогательные классы и классы.

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

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

Ответ 2

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

Ответ 3

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

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

Ответ 4

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

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

Ответ 5

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

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

Ответ 6

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

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

Ответ 7

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

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

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

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

Ответ 8

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

Ответ 9

Может быть, потому, что вы используете Enclosed.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(){
}
}

}