«1. Обзор

В этой статье мы поймем, почему в JUnit возникает ошибка java.lang.NoClassDefFoundError и как ее исправить. Эта проблема в основном связана с конфигурациями IDE. Поэтому мы сосредоточимся на самых популярных IDE: Visual Studio Code, Eclipse и IntelliJ, чтобы воспроизвести и устранить эту ошибку.

2. Что такое java.lang.NoClassDefFoundError?

Когда среда выполнения Java запускает программу Java, она не загружает сразу все классы и зависимости. Вместо этого он вызывает загрузчик классов Java для загрузки классов в память по мере необходимости. Если при загрузке класса загрузчик классов не может найти определение класса, он выдает ошибку NoClassDefFoundError.

Есть несколько причин, по которым Java не может найти определение класса, а именно:

    Отсутствует несколько зависимых jar-файлов, что является наиболее распространенной причиной. Все банки добавляются как зависимости, но по неправильному пути. Несоответствие версий в зависимостях.

3. Код VS

Для написания тестовых примеров Junit4 нам потребуется jar-файл Junit4. Однако Junit4 имеет внутреннюю зависимость от jar ядра hamcrest.

Если мы пропустим добавление jar hamcrest-core в качестве зависимости в наш путь к классам, Java выдаст ошибку NoClassDefFoundError. Путь к классам выглядит следующим образом:

Еще один сценарий: мы добавили обе банки, но их версии не совпадают. Например, если мы добавили JUnit jar версии 4.13.2 и jar hamcrest-core версии 2.2, выдается ошибка NoClassDefFoundError:

В обоих случаях выводится одна и та же трассировка стека:

Чтобы устранить ошибку в обоих сценариях (отсутствующие зависимости и несоответствие версий), нам нужно добавить правильные зависимости. Правильные зависимости для Junit4: junit-4.13.2.jar и hamcrest-core-1.3.jar. Добавление этих двух банок в зависимости (ссылочные библиотеки) устраняет ошибку. Инструкции по добавлению и удалению внешних банок в VS Code представлены здесь. Раздел библиотеки, на который мы ссылаемся, должен быть настроен следующим образом:

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

4. Eclipse

В Eclipse IDE, которая поддерживает Java 9 и выше, у нас есть путь к классам и путь к модулю. Чтобы разрешить зависимость модуля, мы используем путь к модулю. Однако добавление внешних jar-файлов в путь к модулю не делает их доступными для загрузчика классов. Следовательно, загрузчик классов считает их отсутствующими зависимостями и выдает ошибку NoClassDefFoundError.

Следовательно, если наша зависимость выглядит так, как показано на изображении ниже, выполнение тестового примера Junit приводит к ошибке NoClassDefFoundError:

Трассировка стека, сгенерированная при запуске теста JUnit:

В Eclipse нам нужно добавить банки в пути к классам, а не в пути к модулю. Итак, чтобы корректно добавить внешние jar-ы, следуйте по пути:

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)

правой кнопкой мыши на Project -\u003e Build Path -\u003e Configure Build Path

В открывшемся окне убираем jar-ы из-под пути к модулю и добавляем их под classpath. Это устраняет ошибку NoClassDefFoundError. Правильный путь к классам для запуска JUnit должен быть примерно таким:

5. IntelliJ

Для запуска тестовых случаев JUnit 5 требуется как механизм Jupiter, так и Jupiter API. Механизм Jupiter внутренне зависит от API Jupiter, поэтому в большинстве случаев достаточно добавить только зависимость механизма Jupiter в pom.xml. Однако добавление только зависимости Jupiter API в наш pom.xml и отсутствие зависимости механизма 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>

В IntelliJ, чтобы исправить зависимости , нам нужно исправить файл pom.xml. Исправленный pom.xml выглядит следующим образом:

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

В качестве альтернативы мы можем добавить junit-jupiter-engine, так как его добавление автоматически добавляет jar junit-jupiter-api в путь к классам и устраняет ошибку.

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

6. Резюме

В этой статье мы рассмотрели различные причины возникновения ошибки java.lang.NoClassDefFoundError в JUnit. Мы также видели, как мы устраняем ошибку в разных IDE. Весь код для этого руководства доступен на GitHub.

«