In this article, we're going to learn how to fix the NoSuchMethodError and NoClassDefFoundError JUnit errors. Such problems usually occur when we have two different JUnit versions in our classpath. This situation may occur, for example, when the project's JUnit version is different from the one that is used in a Maven or Gradle dependency.
2. JUnit's NoClassDefFoundError in a Spring Project
Let's say that we have a Maven project using Spring Boot 2.1.2 and the Spring Boot Starter Test dependency. With such dependency, we can write and run automated tests using JUnit 5.3.2, which is the JUnit version of the spring-boot-test dependency.
Now, suppose we'll continue using Spring Boot 2.1.2. However, we want to use JUnit 5.7.1. A possible approach would be the inclusion of the junit-jupiter-api, junit-jupiter-params, junit-jupiter-engine, and junit-platform-launcher dependencies in our pom.xml file:
<dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter-api</artifactId> <version>5.7.1</version> <scope>test</scope> </dependency> ...
Nevertheless, in this case, we'll get a NoClassDefFoundError when we run our tests:
[ERROR] java.lang.NoClassDefFoundError: org/junit/platform/commons/util/ClassNamePatternFilterUtils
Instead of the NoClassDefFoundError, a NoSuchMethodError will occur if we migrate to JUnit 5.4.0.
3. Understanding and Fixing the Error
As illustrated in the previous section, we ended up with a NoClassDefFoundError when we tried to migrate our JUnit version from 5.3.2 to 5.7.1.
The error occurred because our classpath ended up having two different versions of JUnit. Therefore, our project was compiled with a newer version of JUnit (5.7.1) but found an older version (5.3.2) at runtime. As a result, the JUnit launcher tried to use a class that is not available in the older version of JUnit.
Next, we're going to learn different solutions for fixing this error.
3.1. Overriding the JUnit Version of Spring
An effective approach for fixing the error in our example is to override the JUnit version managed by Spring:
<properties> <junit-jupiter.version>5.7.1</junit-jupiter.version> </properties>
Now, we can also replace our JUnit dependencies with the following one:
<dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter</artifactId> </dependency>
This single dependency will include junit-jupiter-api, junit-jupiter-params, and junit-jupiter-engine. The junit-platform-launcher dependency is usually necessary only when we need to run our JUnit tests programmatically.
Similarly, we can also override the managed version in a Gradle project:
ext['junit-jupiter.version'] = '5.7.1'
3.2. Solution for Any Project
In the previous section, we learned how to fix the NoSuchMethodError and NoClassDefFoundError JUnit errors in a Spring project, which is the most common scenario. However, if these errors are happening and our project does not use Spring, we can try to fix the collision of dependencies in Maven.
Similar to what happened in our example with Spring, a project may have multiple versions of JUnit due to transitive dependencies. For such a scenario, we have a detailed tutorial on how to resolve the collisions in Maven.
In this tutorial, we reproduced and learned how to fix the NoSuchMethodError and NoClassDefFoundError JUnit errors. The code snippets, as always, can be found over on GitHub. Please notice that, in this source code example, we override the JUnit version in the pom.xml file of the parent project.