JUnit 4.8.1 使用中に、
public class FooTest extends TestCase { @Test public void foo { assertTrue(true); } }
がElipse/Maven双方から認識されない現象に遭遇したのでメモ。
環境:
JUnit : 4.8.1 POM : <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.8.1</version> <scope>test</scope> </dependency> Maven : 2.2.1 Eclipse : 3.5 Galileo org.eclipse.jdt.junit (3.5.1.r351_v20090708-0800) org.eclipse.jdt.junit.runtime (3.4.100.v20090513-2000) org.eclipse.jdt.junit4.runtime (1.1.0.v20090513-2000) org.eclipse.pde.junit.runtime (3.4.0.v20090527) org.junit (3.8.2.v20090203-1005) org.junit4 (4.5.0.v20090824) JDK 1.6.12 Windows XP SP2 / 2GB RAM / Pen4 HT
前掲のFooTestクラス一つだけの状態で、Eclipse上からJUnit実行 or "mvn test" を実行すると「テストケースが見つかりません」という趣旨のエラーになる。
発生時のスタックトレース(Eclipse経由):
junit.framework.AssertionFailedError: No tests found in echoes.act9.protocol.FooTest at junit.framework.Assert.fail(Assert.java:47) at junit.framework.TestSuite$1.runTest(TestSuite.java:97) at junit.framework.TestCase.runBare(TestCase.java:134) at junit.framework.TestResult$1.protect(TestResult.java:110) at junit.framework.TestResult.runProtected(TestResult.java:128) at junit.framework.TestResult.run(TestResult.java:113) at junit.framework.TestCase.run(TestCase.java:124) at junit.framework.TestSuite.runTest(TestSuite.java:232) at junit.framework.TestSuite.run(TestSuite.java:227) at org.junit.internal.runners.JUnit38ClassRunner.run(JUnit38ClassRunner.java:83) at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:46) at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
発生時のスタックトレース(Maven経由):
------------------------------------------------------------------------------- Test set: echoes.act9.protocol.FooTest ------------------------------------------------------------------------------- Tests run: 1, Failures: 1, Errors: 0, Skipped: 0, Time elapsed: 0.094 sec <<< FAILURE! warning(junit.framework.TestSuite$1) Time elapsed: 0.016 sec <<< FAILURE! junit.framework.AssertionFailedError: No tests found in echoes.act9.protocol.FooTest at junit.framework.Assert.fail(Assert.java:47) at junit.framework.TestSuite$1.runTest(TestSuite.java:97) at junit.framework.TestCase.runBare(TestCase.java:134) at junit.framework.TestResult$1.protect(TestResult.java:110) at junit.framework.TestResult.runProtected(TestResult.java:128) at junit.framework.TestResult.run(TestResult.java:113) at junit.framework.TestCase.run(TestCase.java:124) at junit.framework.TestSuite.runTest(TestSuite.java:232) at junit.framework.TestSuite.run(TestSuite.java:227) at org.junit.internal.runners.JUnit38ClassRunner.run(JUnit38ClassRunner.java:83) at org.apache.maven.surefire.junit4.JUnit4TestSet.execute(JUnit4TestSet.java:62) at org.apache.maven.surefire.suite.AbstractDirectoryTestSuite.executeTestSet(AbstractDirectoryTestSuite.java:140) at org.apache.maven.surefire.suite.AbstractDirectoryTestSuite.execute(AbstractDirectoryTestSuite.java:127) at org.apache.maven.surefire.Surefire.run(Surefire.java:177) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at org.apache.maven.surefire.booter.SurefireBooter.runSuitesInProcess(SurefireBooter.java:345) at org.apache.maven.surefire.booter.SurefireBooter.main(SurefireBooter.java:1009)
メソッド名に"test"接頭辞を付与すると認識され、テストケースが実行される。
ClassRunnerの内部判定処理でJUnit3.8.x用のClassRunnerが選択されてしまう為、"@Test"アノテーションが認識されなかったことが原因。
Eclipse上のスタックトレース:
... at org.junit.internal.runners.JUnit38ClassRunner.run(JUnit38ClassRunner.java:83) at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:46) ...
Maven上のスタックトレース:
... at org.junit.internal.runners.JUnit38ClassRunner.run(JUnit38ClassRunner.java:83) at org.apache.maven.surefire.junit4.JUnit4TestSet.execute(JUnit4TestSet.java:62) ...
参考:
テストクラスの宣言に以下のアノテーションを付与する。
... import org.junit.runner.RunWith; import org.junit.runners.JUnit4; ... @RunWith(JUnit4.class) public class FooTest extends TestCase { ...
上に挙げた "RunWith helps JUnit" の記事では "JUnit4ClassRunner.class" を使っているが、JUnit-4.8.1においてはdeprecatedにされている。JavaDocを調べたところ、4.8.1においては"org.junit.runners.JUnit4"を使うと良いようだ。
"org.junit.runners.BlockJUnit4ClassRunner" というのもあるが、JavaDocで
Developers wanting to explicitly tag a class as a JUnit 4 class should use @RunWith(JUnit4.class), not, for example in JUnit 4.5, @RunWith(BlockJUnit4ClassRunner.class).
とあるため、JUnit4.classの方を採用した。
以上の対処により、Eclipse, Maven 共に@Testアノテーションが認識されるようになった。