2009-09-20 16 views
11

Mam klasę testową, napisaną w składni JUnit4, która może być uruchamiana w czasie zaćmienia z opcją "uruchom jako junit" bez niepowodzenia. Kiedy uruchomić ten sam test za pośrednictwem mrówek cel otrzymuję ten błąd:Czy klasy testowe JUnit4 wymagają publicznego konstruktora 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) 

nie mam żadnego publicznego konstruktora arg w klasie, ale jest to naprawdę konieczne?

To jest mój cel mrówka

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

Klasa testu nie mają konstruktorów, ale to ma wewnętrzną klasę z domyślnym modyfikatora. Ma również anonimową klasę wewnętrzną. Obie klasy wewnętrzne dają "Klasa testowa powinna mieć publiczny błąd konstruktora o zerowym argumencie". Używam wersji Ant 1.7.1 i JUnit 4.7

Odpowiedz

3

Dziękuję wszystkim za poświęcony czas i odpowiedzi. Znalazłem rozwiązanie. Poprzednio uważałem, że dane wejściowe dla części batchtest mojej ant ant powinny być plikami .class, ale możliwe jest również użycie plików .java.

To rozwiązało problem. Teraz nie narzeka już na wewnętrzne klasy, w których brakuje publicznych konstruktorów.

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

Moim jedynym problemem jest teraz, że muszę odfiltrować klas testowych bez testów, w celu uniknięcia „żadne metody Runnable” -error. Oznacza to, że klasy pomocnicze i użytkowe.

Musi istnieć bardziej eleganckie rozwiązanie niż moje. Jednym z rozwiązań może być konwencja nazewnicza zgodnie z sugestią [JUnit: how to avoid "no runnable methods" in test utils classes.

Klasy pomocnicze nie zawierają funkcji @Test annotaion. Musi być możliwe wykorzystanie tego w pewien sposób ...

+0

Spróbuj wykluczyć **/* Helper.java. –

1

Wystąpienia twoich klas testowych muszą być wykonane jakoś. Możesz utworzyć test no-arg, który dodaje instancje testowe utworzone w jakiś inny sposób, co może być przydatne do parametryzowania testów (lub tak czy inaczej było w JUnit 3).

Ale dlaczego miałbyś tłumić syntetyczny konstruktor no-arg?

1

Po konstruktor no-Arg pozwala zajęcia testowe należy agregować do apartamentów:

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

wierzę trzeba no-args konstruktora, ale jeśli nie deklaruje żadnych konstruktorów Java stworzy syntetyczny jeden dla Ciebie. Jesteś pewien, że ant-task nie zbiera innej klasy; taki, który po prostu dzieje się zgodnie z ustaloną konwencją nazewnictwa (*Test lub Test*)?

5

Musisz mieć domyślny konstruktor dla sprawy testowej. W przeciwnym razie biegacz nie wie, jak utworzyć instancję klasy. Wygląda na to, że masz konstruktor z argumentami. Java nie tworzy domyślnego konstruktora, jeśli masz już konstruktor.

Generalnie powinieneś unikać konstruktorów w przypadkach testowych. Jeśli chcesz dokonać inicjalizacji, napisz metodę init i dodaj ją przy pomocy @BeforeClass. Korzyścią jest to, że śledzenie stosu będzie znacznie czystsze, jeśli wystąpią jakiekolwiek błędy. Jak widać, ślad stosu konstruktora jest naprawdę mylący dla większości ludzi.

5

Eclipse używa innej implementacji do uruchamiania przypadków testowych JUnit4 - ma własny tester. Zdarza się, że różni się od tego używanego przez Ant - domyślnego dostępnego w dystrybucji JUnit, i jest przyczyną rozbieżności odnotowanych w zachowaniu wykonawczym środowisk w Ant i Eclipse.

Przyjrzenie się kodowi źródłowemu JUnit 4.3.1, 4.5 i 4.7 (szczególnie tego z testrunnerów) ujawnia, że ​​klasy testowe muszą mieć publiczny konstruktor o zerowym argumencie. Zauważ, że domyślnym runner w JUnit v4.7 jest BlockJUnit4ClassRunner. Zauważysz, że javadocs (co za szkoda!) Zawierają reguły, których należy przestrzegać, co stanowi dobrze uformowaną klasę testową - jednym z nich jest publiczny konstruktor bezargumentowy.

+0

myślałem tak samo jak ty. Że ma to coś wspólnego z junit3 vs junit4, ale o ile widzę w stosie, jest to w rzeczywistości zaangażowany JUnit4TestAdapter. –

+0

Cóż, rzuciłem okiem na źródła Ant 1.7.1. W JUnitTestRunner.java (wiersz 386, który pojawia się w śladzie stosu) tworzona jest instancja TestSuite, tylko jeśli spełnione są warunki wstępne. –

+0

Oops my bad, linia 396 tworzy TestSuite podczas gdy 386 tworzy JUnit4TestAdapter. –

0

Niestatyczne klasy wewnętrzne mają ukryty konstruktor, który bierze klasę zewnętrzną jako argument. Jeśli twoje wewnętrzne klasy nie dzielą się stanem z zewnętrznymi klasami, po prostu je zrób static.

1

Dla starszych wersji junit, jeśli masz słowo "Test" w swojej wewnętrznej klasie, ten problem wystąpi.

Wpadliśmy na ten problem, implementując wzorzec podklasy do testowania, podając nazwę podklasy, np. FooForTest. Zmieniając nazwę na FooSubclass, problem został rozwiązany.

Zobacz powyższy komentarz @Vineet Reynolds, aby uzyskać więcej informacji na temat wersji junit objętych problemem, i dlaczego tak się dzieje dla ant, ale nie zaćmienie.

Nadzieję, że pomaga!

0

Może być ponieważ używasz Enclosed.class, a następnie załączone klas musi być statyczny

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

}

Powiązane problemy