JUnitのjava.lang.NoClassDefFoundError
1. 概要
この記事では、 java.lang.NoClassDefFoundErrorがJUnitで発生する理由とその修正方法について説明します。 この問題は、主にIDEの構成に関連しています。 したがって、このエラーを再現して解決するために、最も人気のあるIDEであるVisual Studio Code、Eclipse、およびIntelliJに焦点を当てます。
2. java .lang.NoClassDefFoundError とは何ですか?
JavaランタイムがJavaプログラムを実行する場合、すべてのクラスと依存関係を一度にロードするわけではありません。 代わりに、Javaクラスローダーを呼び出して、必要に応じてメモリにクラスをロードします。クラスのロード中に、クラスローダーがクラスの定義を見つけられない場合、NoClassDefFoundErrorをスローします。
Javaがクラスの定義を見つけられない理由はいくつかあります。それは次のとおりです。
- 最も一般的な理由であるいくつかの依存するjarファイルがありません。
- すべてのjarは依存関係として追加されますが、パスが間違っています。
- 依存関係のバージョンの不一致。
3. VSコード
Junit4テストケースを作成するには、Junit4jarが必要です。 ただし、Junit4はhamcrest-corejarに内部依存しています。
クラスパスの依存関係としてhamcrest-core jarを追加し忘れた場合、JavaはNoClassDefFoundErrorをスローします。 クラスパスは次のとおりです。
もう1つのシナリオは、両方のjarを追加したが、バージョンが一致しない場合です。 たとえば、JUnitjarバージョン4.13.2とhamcrest-core jarバージョン2.2を追加した場合、NoClassDefFoundErrorがスローされます。
どちらの場合も、同じスタックトレースが出力されます。
java.lang.NoClassDefFoundError: org/hamcrest/SelfDescribing
at java.base/java.lang.ClassLoader.defineClass1(Native Method)
at java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:1010)
at java.base/java.security.SecureClassLoader.defineClass(SecureClassLoader.java:150)
at java.base/jdk.internal.loader.BuiltinClassLoader.defineClass(BuiltinClassLoader.java:855)
at java.base/jdk.internal.loader.BuiltinClassLoader.findClassOnClassPathOrNull(BuiltinClassLoader.java:753)
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClassOrNull(BuiltinClassLoader.java:676)
...
両方のシナリオ(依存関係の欠落とバージョンの不一致)のエラーを解決するには、正しい依存関係を追加する必要があります。 Junit4の場合の正しい依存関係は、junit-4.13.2.jarとhamcrest-core-1.3.jarです。 これらの2つのjarを依存関係(参照ライブラリ)に追加すると、エラーが解決されます。 VSCodeで外部jarを追加および削除する手順はここにあります。 参照されるライブラリセクションは、次のように設定する必要があります。
4. Eclipse
Java9以降をサポートするEclipseIDEには、クラスパスとモジュールパスがあります。 モジュールの依存関係を解決するには、モジュールパスを使用します。 ただし、モジュールパスに外部jarを追加しても、クラスローダーで使用できるようにはなりません。 したがって、クラスローダーはそれらを依存関係が欠落していると見なし、NoClassDefFoundErrorをスローします。
したがって、依存関係が次の画像のようになっている場合、Junitテストケースを実行すると、 NoClassDefFoundError:になります。
JUnitテストの実行時に生成されるスタックトレースは次のとおりです。
java.lang.NoClassDefFoundError: org/junit/runner/manipulation/Filter
at java.base/java.lang.Class.forName0(Native Method)
at java.base/java.lang.Class.forName(Class.java:377)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.loadTestLoaderClass(RemoteTestRunner.java:381)
Eclipseでは、モジュールパスではなくクラスパスの下にjarを追加する必要があります。 したがって、外部jarを正しく追加するには、次のパスに従います。
[プロジェクト]->[ビルドパス]->[ビルドパスの構成]を右クリックします
開いたウィンドウで、モジュールパスの下からjarを削除し、クラスパスの下に追加します。 これにより、NoClassDefFoundErrorが解決されます。 JUnitを実行するための正しいクラスパスは、次のようになります。
5. IntelliJ
JUnit5テストケースを実行するにはJupiterエンジンとJupiterAPIの両方が必要です。Jupiterエンジンは内部的にJupiterAPIに依存しているため、ほとんどの場合、Jupiterエンジンの依存関係だけを追加するだけで十分です。 pom.xml。 ただし、 pom.xmlにJupiterAPI依存関係のみを追加し、Jupiterエンジン依存関係が欠落していると、NoClassDefFoundErrorが発生します。
pom.xmlの誤った設定は次のようになります。
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
この設定で簡単なテストケースを実行すると、次のスタックトレースが生成されます。
Exception in thread "main" java.lang.NoClassDefFoundError: org/junit/platform/engine/TestDescriptor
at java.base/java.lang.Class.forName0(Native Method)
at java.base/java.lang.Class.forName(Class.java:375)
at com.intellij.rt.junit.JUnitStarter.getAgentClass(JUnitStarter.java:230)
....
IntelliJでは、依存関係を修正するには、pom.xmlを修正する必要があります。 修正されたpom.xmlは次のようになります。
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
または、 junit-jupiter-engine を追加すると、 junit-jupiter-api jarがクラスパスに自動的に追加され、エラーが解決されるため、追加できます。
6. 概要
この記事では、java.lang.NoClassDefFoundErrorがJUnitで発生するさまざまな理由を確認しました。 また、さまざまなIDEでエラーを解決する方法も確認しました。 このチュートリアルのコード全体は、GitHubでから入手できます。