The java.lang.NoClassDefFoundError in JUnit – JUnit中的java.lang.NoClassDefFoundError

最后修改: 2021年 7月 5日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

In this article, we’ll understand why the java.lang.NoClassDefFoundError occurs in JUnit and how to fix it. This issue is mainly related to IDE’s configurations. Therefore, we’ll be focusing on the most popular IDEs: Visual Studio Code, Eclipse, and IntelliJ to reproduce and resolve this error.

在本文中,我们将了解 java.lang.NoClassDefFoundErrorJUnit中出现的原因以及如何修复它。这个问题主要与IDE的配置有关。因此,我们将把重点放在最流行的IDE上。Visual Studio Code、Eclipse和IntelliJ来重现和解决这个错误。

2. What Is java.lang.NoClassDefFoundError?

2.什么是java.lang.NoClassDefFoundError

When the Java Runtime runs a Java program, it does not load all the classes and dependencies at once. Instead, it calls upon the Java Classloader to load classes in memory as-and-when-required. While loading a class, if the Classloader cannot find the class’s definition, it throws the  NoClassDefFoundError.

当Java Runtime运行一个Java程序时,它不会一次性加载所有的类和依赖关系。在加载一个类时,如果Classloader找不到该类的定义,它会抛出NoClassDefFoundError

There are a couple of reasons for which Java cannot find the class’s definition, which are:

有几个原因导致Java无法找到该类的定义,这就是。

  • Missing a few dependent jars which is the most common reason.
  • All jars are added as dependencies but in the wrong path.
  • Version mismatches in the dependencies.

3. VS Code

3.美国法典

For writing Junit4 test cases, we require the Junit4 jar. However, the Junit4 has an internal dependency on the hamcrest-core jar.

为了编写Junit4测试用例,我们需要Junit4 jar。然而,Junit4有一个对 hamcrest-core jar的内部依赖。

If we miss adding the hamcrest-core jar as a dependency in our classpath, Java throws the NoClassDefFoundError. The classpath is as follows:

如果我们没有在classpath中添加hamcrest-core jar作为依赖项,Java会抛出NoClassDefFoundError。classpath如下。

One other scenario is when we added both the jars, but the versions don’t match. For example, if we have added JUnit jar version 4.13.2 and the hamcrest-core jar version 2.2, the NoClassDefFoundError is thrown:

还有一种情况是,我们同时添加了两个jar,但版本不匹配。例如,如果我们添加了JUnit jar版本4.13.2和hamcrest-core jar版本2.2,就会抛出NoClassDefFoundError

 

In both cases, the same stack trace is printed:

在这两种情况下,都会打印相同的堆栈跟踪。

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

To resolve the error in both the scenarios (missing dependencies and version mismatch), we need to add the correct dependencies. The correct dependencies in the case of Junit4 are junit-4.13.2.jar and hamcrest-core-1.3.jar. Adding these two jars in the dependencies (Referenced Libraries) resolves the error. The instructions to add and remove external jars in VS Code are present here. Our referenced library section should be set up as:

为了解决这两种情况下的错误(缺失的依赖关系和版本不匹配),我们需要添加正确的依赖关系。Junit4的正确依赖是junit-4.13.2.jarhamcrest-core-1.3.jar。在依赖项(参考库)中添加这两个jar可以解决这个错误。在VS Code中添加和删除外部罐子的说明见这里。我们的引用库部分应该被设置为。

4. Eclipse

4.日蚀

In Eclipse IDE that supports Java 9 and above, we have a classpath and a module path. To resolve module dependency, we use the module path. However, adding external jars in the module path does not make them available for the class loader. Hence the class loader considers them as missing dependencies and throws the NoClassDefFoundError.

在支持 Java 9 及以上版本的 Eclipse IDE 中,我们有一个 classpath 和一个模块路径。为了解决模块的依赖性,我们使用模块路径。然而,在模块路径中添加外部罐子并不能使它们对类加载器可用。因此,类加载器认为它们是缺失的依赖,并抛出了NoClassDefFoundError

Hence if our dependency looks like the below image, running a Junit test case results in a NoClassDefFoundError:

因此,如果我们的依赖关系看起来像下面的图片,运行Junit测试案例的结果是NoClassDefFoundError:

The stack trace generated on running the JUnit test is:

运行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)

In Eclipse, we need to add the jars under the classpath and not in the module path. So, to add external jars correctly, follow the path:

在Eclipse中,我们需要在classpath下添加jars,而不是在模块路径下。因此,要正确地添加外部的jars,请遵循这个路径。

right-click on the Project -> Build Path -> Configure Build Path

右键点击项目->构建路径->配置构建路径

In the window that opens, remove the jars from under the module path and add them under the classpath. This resolves the NoClassDefFoundError. The correct classpath for running JUnit should be similar to:

在打开的窗口中,将模块路径下的jars移除,并将其添加到classpath下。这就解决了NoClassDefFoundError。运行JUnit的正确classpath应该类似于。

5. IntelliJ

5.智慧的力量

Running JUnit 5 test cases requires both the Jupiter engine and Jupiter API. The Jupiter engine is internally dependent on the Jupiter API, and hence most of the time,  it is sufficient to add just the Jupiter engine dependency in the pom.xml. However, Adding only the Jupiter API dependency in our pom.xml and missing the Jupiter engine dependency results in the NoClassDefFoundError.

运行JUnit 5测试用例需要Jupiter引擎和Jupiter API。Jupiter引擎在内部依赖于Jupiter API,因此大多数情况下,只在pom.xml中添加Jupiter引擎依赖即可。然而,在我们的pom.xml中只添加Jupiter API的依赖性而缺少Jupiter引擎的依赖性会导致NoClassDefFoundError

The incorrect setup in the pom.xml would be like this:

pom.xml中的不正确设置将是这样的。

<dependencies>
    <dependency>
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter-api</artifactId>
        <version>5.8.1</version>
        <scope>test</scope>
    </dependency>
</dependencies>

Running a simple test case with this setup results in the following stack trace:

用这个设置运行一个简单的测试用例,会产生以下堆栈跟踪。

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

In IntelliJ, to correct the dependencies, we need to correct the pom.xml. The corrected pom.xml looks like this:

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

Alternatively, we can add junit-jupiter-engine since adding it automatically adds the junit-jupiter-api jar to the classpath and resolves the error.

另外,我们可以添加junit-jupiter-engine,因为添加它可以自动将junit-jupiter-api jar添加到classpath并解决错误。

6. Summary

6.归纳总结

In this article, we saw different reasons for the java.lang.NoClassDefFoundError to occur in JUnit. We also saw how we resolve the error in different IDEs. The entire code for this tutorial is available over on GitHub.

在这篇文章中,我们看到了JUnit中出现java.lang.NoClassDefFoundError的不同原因。我们还看到了如何在不同的IDE中解决这个错误。本教程的全部代码可在 GitHub 上获取