1. 概要

この記事では、 java.lang.NoClassDefFoundErrorJUnitで発生する理由とその修正方法について説明します。 この問題は、主に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.jarhamcrest-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から入手できます。