網頁

2019/8/31

JUnit 執行時出現錯誤 java.lang.NoClassDefFoundError

今天在Spring Boot + Gradle新的專案執行JUnit測試時,出現java.lang.NoClassDefFoundError的錯誤,過程及原因如下。


先說結論,造成錯誤的原因是在Gradle專案的build.gradle引入了不存在的依賴函式庫。


今天(2019/8/30)根據Apache Commons NumbersGithub頁面說明,其Maven Central位置如下:

<dependency>
  <groupId>org.apache.commons</groupId>
  <artifactId>commons-numbers</artifactId>
  <version>1.0</version>
</dependency>

但之後不論在Maven Central或透過Maven都無法從上述的位置下載,也就是被Apache Commons Numbers的Github說明給唬了。


因此我根據上面的資訊在Spring Boot + Gradle新專案的build.gradle設定了以下試圖引入依賴函式庫。因為是新的專案,所以只是先引進來以後可以使用。

dependencies {
    ...
    implementation 'org.apache.commons:commons-numbers:1.0'
    ...
}

但在在Eclipse執行[Refresh Gradle Project]的時候沒有注意到Eclipse的Console出現下面訊息。

Could not resolve: org.apache.commons:commons-numbers:1.0

CONFIGURE SUCCESSFUL in 2s

也就是找不到依賴的jar檔,然後在Eclipse整個專案也沒任何錯誤提示,導致不論在JUnit 4執行掛有@RunWith(SpringRunner.class)的測試類別的JUnit測試時出現下面錯誤。

java.lang.NoClassDefFoundError: org/junit/runner/manipulation/Filter
 at java.lang.Class.forName0(Native Method)
 at java.lang.Class.forName(Class.java:264)
 at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.loadTestLoaderClass(RemoteTestRunner.java:380)
 at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.createRawTestLoader(RemoteTestRunner.java:370)
 at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.createLoader(RemoteTestRunner.java:365)
 at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.defaultInit(RemoteTestRunner.java:309)
 at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.init(RemoteTestRunner.java:224)
 at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:208)
Caused by: java.lang.ClassNotFoundException: org.junit.runner.manipulation.Filter
 at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
 at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
 at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:349)
 at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
 ... 8 more

或在JUnit 5執行掛有@ExtendWith(SpringExtension.class)的測試類別的JUnit測試時出現下面錯誤。

java.lang.NoClassDefFoundError: org/junit/platform/commons/util/Preconditions
 at org.junit.platform.launcher.core.LauncherFactory.create(LauncherFactory.java:83)
 at org.junit.platform.launcher.core.LauncherFactory.create(LauncherFactory.java:67)
 at org.eclipse.jdt.internal.junit5.runner.JUnit5TestLoader.(JUnit5TestLoader.java:34)
 at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
 at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
 at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
 at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
 at java.lang.Class.newInstance(Class.java:442)
 at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.createRawTestLoader(RemoteTestRunner.java:370)
 at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.createLoader(RemoteTestRunner.java:365)
 at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.defaultInit(RemoteTestRunner.java:309)
 at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.init(RemoteTestRunner.java:224)
 at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:208)
Caused by: java.lang.ClassNotFoundException: org.junit.platform.commons.util.Preconditions
 at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
 at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
 at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:349)
 at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
 ... 13 more

而當我把該不存在的jar檔設定從build.gradle移除並重新執行[Refresh Gradle Project]後就不會出現以上錯誤了,JUnit 4及JUnit 5都可以正常執行。

然後我又試了一下,故意引入另一個不存在的依賴,會引發相同的問題。

總之就是在Eclipse的Gradle專案引入依賴函式庫時,要確認引用的函式庫位置和版本是否正確,如果引用錯誤時只有在執行[Refresh Gradle Project]會在Eclipse的[Console]出現 Could not resolve: <group:module:version> 的提示,但在Eclipse的[Markers]卻不會出現錯誤提示,進一步造成JUnit執行出現如上的錯誤。


這問題搞了我幾乎3個小時才解決。原本一直以為是JUnit還是Gradle設定錯誤造成的。


沒有留言:

張貼留言