Solve ClassNotFoundException: org.junit.platform.engine.EngineDiscoveryListener
안녕하세요. yeTi입니다.
오늘은 Eclipse에서 JUnit을 구동할때 발생하는 Caused by: java.lang.ClassNotFoundException: org.junit.platform.engine.EngineDiscoveryListener
를 해결한 상황을 공유하고자 합니다.
저는 다음과 같은 상황에서 정상적으로 JUnit을 사용하고 있었습니다.
- IDE : STS-4.5.1.RELEASE
- Java : openjdk-12.0.1 (JavaSE-11)
- SpringBoot : 2.2.4.RELEASE
- Gradle : 6.0.1
- JUnit : 5.5.2
오류
그런데 STS에서 업데이트 안내가 떠서 업데이트를 하고나니(4.6.0.RELEASE) 다음과 같은 오류가 발생하면서 JUnit이 동작하지 않았습니다.
java.lang.NoClassDefFoundError: org/junit/platform/engine/EngineDiscoveryListener
at java.base/java.lang.ClassLoader.defineClass1(Native Method)
at java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:1016)
at java.base/java.security.SecureClassLoader.defineClass(SecureClassLoader.java:151)
at java.base/jdk.internal.loader.BuiltinClassLoader.defineClass(BuiltinClassLoader.java:802)
at java.base/jdk.internal.loader.BuiltinClassLoader.findClassOnClassPathOrNull(BuiltinClassLoader.java:700)
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClassOrNull(BuiltinClassLoader.java:623)
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:581)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
at org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder.getLauncherDiscoveryListener(LauncherDiscoveryRequestBuilder.java:241)
at org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder.build(LauncherDiscoveryRequestBuilder.java:235)
at org.eclipse.jdt.internal.junit5.runner.JUnit5TestLoader.createFilteredTest(JUnit5TestLoader.java:70)
at org.eclipse.jdt.internal.junit5.runner.JUnit5TestLoader.createTest(JUnit5TestLoader.java:64)
at org.eclipse.jdt.internal.junit5.runner.JUnit5TestLoader.loadTests(JUnit5TestLoader.java:53)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:526)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:770)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:464)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:210)
Caused by: java.lang.ClassNotFoundException: org.junit.platform.engine.EngineDiscoveryListener
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:583)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
... 18 more
잘 동작하던게 오류가 나온 상황이라 의아한 생각에 차근차근 디버깅을 해봤습니다.
원인 분석
일단 org.junit.platform.engine.EngineDiscoveryListener
를 찾아보니 junit-platform-engine-1.5.2.jar
내에 존재하지 않는것을 확인하였고, JUnit5 - Docs를 확인한 결과 1.6
부터 추가된것을 알수 있었습니다.
그리고는 혹시 이 문제가 STS의 버전에 따른 문제인지 확인해보기 위해 다음과 같이 테스트를 해봤습니다.
Gradle Test
로는 정상 동작함- 신규 프로젝트의 빌드툴을
Gradle
로 만들어서 확인하니 동일한 현상이 발생하는 것을 확인 - 신규 프로젝트의 빌드툴을
Maven
으로 변경해서 확인하니 정상 동작함 - 이전 버전인
STS-4.4.1.RELEASE
를 다운받아서 프로젝트를 새로 만드니 정상 동작함 - 현재 버전인
STS-4.6.0.RELEASE
,Eclipse-2020-03
에서 다운받아서 프로젝트를 새로 만드니 동일한 현상이 발생하는 것을 확인
이처럼 STS에 Gradle
을 사용한 경우에 발생하는 것을 확인했고, STS의 버전업과 관련이 있는것을 확인했습니다.
그렇다면, 왜 업그레이드된 STS에서 1.6
을 찾고 있을까요? STS에서 JUnit
의 버전이 변경됐을까요?
해결
구글링 결과, EclipseでJUnit5がjava.lang.NoClassDefFoundError: org/junit/platform/engine/EngineDiscoveryListenerになる- Qiita에서 제시한대로 testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
의존성을 추가했더니 정상 동작하는것을 확인했습니다.
상세 분석
junit-platform-launcher
의 버전을 1.6.0
으로 변경하면 문제 상황이 동일하게 발생하는것을 확인하였으므로 junit의 launcher의 변경에 따른 문제로 볼 수 있습니다.
STS의 버전별 차이점을 확인해보니 eclipse plugins
에 존재하는 org.junit.platform.launcher
의 버전 차이가 있었습니다.
STS-4.4.1.RELEASE
(기존) :1.5.1
STS-4.6.0.RELEASE
(최신) :1.5.1
,1.6.0
Eclipse-2020-03
(최신) :1.6.0
이클립스가 JUnit을 구동하는 절차를 보면 다음과 같습니다.
org.eclipse.jdt.junit.runtime
플러그인에 있는org.eclipse.jdt.internal.junit.runner.RemoteTestRunner
클래스 구동org.eclipse.jdt.junit5.runtime
플러그인에 있는org.eclipse.jdt.internal.junit5.runner.JUnit5TestLoader
클래스를 의존관계로 가짐JUnit5TestLoader
클래스는org.junit.platform.launcher.Launcher
클래스를 의존관계로 가짐
junit-platform-launcher
라이브러리내의Launcher
클래스 load- 우선순위 : classpath -> eclipse plugins내 최신 버전
따라서 STS
가 4.6.0.RELEASE
로 업데이트 된 후 junit-platform-launcher
가 1.6.0
을 사용하게 되면서 org.junit.platform.engine.EngineDiscoveryListener
클래스를 찾게 된 것입니다.
여기에 의존성을 추가하여 classpath
에 junit-platform-launcher:1.5.1
를 추가하여 해당 버전의 launcher
를 사용할 수 있도록 한 것입니다.