我有一个使用 Spock 测试框架编写的单元测试来测试我的 Spring Boot 应用程序。 我已经声明了以下测试依赖项:
spock-spring
:2.3-groovy-4.0spring-boot-starter-test
:3.2.4surefire plugin version
:3.2.2当我运行
mvn test
时,surefire插件无法执行它们,并给出错误:
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-surefire-plugin:3.2.2:test (default-test) on project spockdata:
[ERROR]
[ERROR] Please refer to C:\Users\myfolder\target\surefire-reports for the individual test results.
[ERROR] Please refer to dump files (if any exist) [date].dump, [date]-jvmRun[N].dump and [date].dumpstream.
There was an error in the forked process
'java.util.Set org.junit.platform.engine.TestDescriptor.getAncestors()'
我按照surefire的说明查看了它创建的surefire转储文件,并看到了错误:
java.lang.NoSuchMethodError: 'java.util.Set org.junit.platform.engine.TestDescriptor.getAncestors()'
at org.junit.platform.launcher.core.StackTracePruningEngineExecutionListener.getTestClassNames(StackTracePruningEngineExecutionListener.java:50)
我尝试声明 Spock 的物料清单,
spock-bom
以确保 Spock 的依赖关系一致,但这没有帮助:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.spockframework</groupId>
<artifactId>spock-bom</artifactId>
<version>2.3-groovy-4.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
我也在没有声明
spock-bom
的情况下进行了测试,但仍然收到此错误。
我该如何解决这个问题以及为什么会发生这种情况?
异常中的类
TestDescriptor
来自 org.junit.platform.engine
包。
让我们运行
mvn dependency:tree
(或者 Maven Helper 插件,如果使用 IntelliJ)来查看我们声明的两个依赖项是否有多个版本的 org.junit.platform 组组件:
[INFO] --- dependency:3.6.1:tree (default-cli) @ myspockspringtest ---
...
[INFO] | +- org.junit.jupiter:junit-jupiter:jar:5.10.2:test
[INFO] | | +- org.junit.jupiter:junit-jupiter-api:jar:5.10.2:test
[INFO] | | | +- org.opentest4j:opentest4j:jar:1.3.0:test
[INFO] | | | +- org.junit.platform:junit-platform-commons:jar:1.10.2:test
[INFO] | | | \- org.apiguardian:apiguardian-api:jar:1.1.2:test
[INFO] | | +- org.junit.jupiter:junit-jupiter-params:jar:5.10.2:test
[INFO] | | \- org.junit.jupiter:junit-jupiter-engine:jar:5.10.2:test
...
[INFO] +- org.spockframework:spock-spring:jar:2.3-groovy-4.0:test
[INFO] | +- org.spockframework:spock-core:jar:2.3-groovy-4.0:test
[INFO] | | \- org.junit.platform:junit-platform-engine:jar:1.9.0:test
由此我们可以看出
spock-spring
的junit-platform-engine
:
org.junit.platform:junit-platform-engine:jar:1.9.0:test
看看
spring-boot-starter-test
,它包含一个类似的 1.x 版本 1.10.2
:
org.junit.platform:junit-platform-commons:jar:1.10.2:test
所以也许这两者是冲突的。
我们还可以在 IntelliJ 中使用
Ctrl+N
来查找 TestDescriptor
以查看它来自哪个工件。这告诉我们 TestDescriptor
住在 junit-platform-engine-1.9.0
罐子里。
当存在冲突时,Maven 会在树中映射出依赖关系,并选择到达它的跳数最少的依赖关系。 如果仍然存在冲突,Maven 将选择 pom 中第一个声明的那个。
在这种情况下,来自 spock-spring 的
junit-platform-engine
在层次结构中更接近根(spock-spring 为 3 跳,而 spring-boot-starter-test 为 4 跳),因此 Maven 选择了 Spock 的 1.9.0 依赖项junit-platform-engine
和
因此,我们有以下不匹配导致 1.9.0 引擎找到 1.10.2 中不再存在的方法:
<dependency>
<groupId>org.spockframework</groupId>
<artifactId>spock-spring</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
或者 2. 包含 Spring Boot 物料清单(带或不带 Spock BOM):
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.spockframework</groupId>
<artifactId>spock-bom</artifactId>
<version>2.3-groovy-4.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>3.2.4</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
完成此操作后,这些组件的
mvn dependency:tree
现在看起来像:
[INFO] --- dependency:3.6.1:tree (default-cli) @ myspockspringtest ---
...
[INFO] | +- org.junit.jupiter:junit-jupiter:jar:5.10.2:test
[INFO] | | +- org.junit.jupiter:junit-jupiter-api:jar:5.10.2:test
[INFO] | | | +- org.opentest4j:opentest4j:jar:1.3.0:test
[INFO] | | | +- org.junit.platform:junit-platform-commons:jar:1.10.2:test
[INFO] | | | \- org.apiguardian:apiguardian-api:jar:1.1.2:test
[INFO] | | +- org.junit.jupiter:junit-jupiter-params:jar:5.10.2:test
[INFO] | | \- org.junit.jupiter:junit-jupiter-engine:jar:5.10.2:test
[INFO] | | \- org.junit.platform:junit-platform-engine:jar:1.10.2:test
...
[INFO] +- org.spockframework:spock-spring:jar:2.3-groovy-4.0:test
[INFO] | +- org.spockframework:spock-core:jar:2.3-groovy-4.0:test
[INFO] | \- org.apache.groovy:groovy:jar:4.0.4:test
...
由此我们可以得出结论,junit-platform v1.9中的TestDescriptor.getAncestors()方法在v1.10中被删除了。
为了解决这个问题,我们通过将 junit 的依赖项从我们的依赖项中排除或导入声明所有依赖项的物料清单来确保它们全部同步。