无法集成测试 gradle 多模块 Spring-Boot-Application
Posted
技术标签:
【中文标题】无法集成测试 gradle 多模块 Spring-Boot-Application【英文标题】:Unable to integration-testing gradle multi-module Spring-Boot-Application 【发布时间】:2020-10-02 01:38:17 【问题描述】:在 Gradle 多模块项目中,在其自己的模块中进行引导,我无法使用 MockMvc,因为它需要引用引导模块。我不确定我是否配置错误。基本结构是:
module:一个包含一些 REST-Services 并且需要 testImplementation-Dependency on starter 的模块 starter:应用了 spring-boot-plugin 并依赖于模块的引导模块我使用 Spring-Boot 2.3.1.RELEASE 和 Gradle 6.4 在 github 上设置了一个最小示例,配置如下:
./settings.gradle.kts
rootProject.name = "spring-multimodule-integrationtest"
include("starter", "module")
./build.gradle.kts
subprojects
repositories
jcenter()
dependencies
apply(plugin = "java-library")
"testImplementation"("junit:junit:4.12")
./starter/build.gradle.kts
plugins
id("org.springframework.boot") version "2.3.1.RELEASE"
dependencies
implementation(project(":module"))
./module/build.gradle.kts
dependencies
testImplementation(project(":starter"))
starter-module 只包含一个引用 module-module 的单一类“Starter”:
public class Starter
public String info() return "starter";
public static void main(String[] args)
System.out.println(new Starter().info() + " and " + new Module().info());
module-module(*叹气我应该为这个模块选择一个不同的名字)只包含这个实现类:
public class Module
public String info() return "module";
此外,module-module 有以下测试类进行集成测试:
public class IntegrationTest
@Test public void testSomeLibraryMethod()
final ByteArrayOutputStream out = new ByteArrayOutputStream();
System.setOut(new PrintStream(out));
Starter.main(new String[0]);
assertEquals("starter and module\n", out.toString());
此代码运行良好,直到在“./starter/build.gradle.kts”中应用 spring-boot-plugin。当我在 shell 上发出“干净测试”任务时:
❯ ./gradlew clean test
> Task :module:test FAILED
de.kramhal.multi.IntegrationTest > testSomeLibraryMethod FAILED
java.lang.NoClassDefFoundError at IntegrationTest.java:17
Caused by: java.lang.ClassNotFoundException at IntegrationTest.java:17
1 test completed, 1 failed
在 IDE(确切地说是 IntelliJ)中执行测试时,不会出现此问题。
我已经尝试使用 answer(以及其他几个答案)中建议的 spring-dependency-management,但没有成功。
我做错了什么?
【问题讨论】:
【参考方案1】:首先,我建议重组您的项目,这样您就没有循环依赖。就像现在一样,为了构建starter
,您需要构建module
。为了测试module
,您需要构建starter
。 Gradle 可以做到,但它通常是一种气味。
在故障排除方面:当您遇到这样的测试失败时,请查看测试报告,因为其中包含完整的堆栈跟踪。您应该看到它抱怨找不到Starter
类(Caused by: java.lang.ClassNotFoundException: de.kramhal.multi.Starter
),这是starter
模块中的原因。
您提到了spring-dependency-management
插件,但这仅与管理 Maven 依赖项有关,与此类项目依赖项无关。所以这里用处不大。
我不完全确定这是否是特定于 Windows 的,因为我记得不久前有很多课程围绕性能进行了一些讨论。但我相信java-library
插件会在其他项目中查找jar文件,而不是编译类的文件夹。这对您来说是个问题,因为spring-boot
插件默认禁用标准jar
任务,而是通过bootJar
任务创建“胖” jar 文件。因为您既需要用于打包应用程序以独立运行的胖 jar,也需要将其作为依赖项使用的普通 jar,因此您需要对 starter
项目(Kotlin DSL)进行一些调整:
tasks
jar
enabled = true
bootJar
archiveClassifier.set("boot")
这将启用正常的jar文件,但由于名称会与bootJar
任务生成的名称冲突,您需要重命名其中一个。我选择重命名bootJar
一个。
我不知道为什么该测试在 IntelliJ 中对您有效,因为默认情况下应该将所有内容委托给 Gradle。但也许你有一个旧版本,或者做了一些手动配置让 IntelliJ 编译和运行你的测试。
【讨论】:
先生!非常感谢您的解释。我没有从失败中得到这个想法,罐子丢失了,它本身就丢失了。我本可以想到这个想法,因为威尔金索纳已经解释了here。另外,我现在看到该链接在转到依赖管理而不是 packaging 时很烦人。 关于循环依赖:我知道这很不寻常,我个人更希望不要让测试依赖于不同的模块。使用 MockMvc 实现集成测试(需要知道“SpringBootApplication”注释类),有哪个选项?我只能考虑根据开胃菜和咖啡(收银员也一样)创建一个单独的模块咖啡集成测试。 为了更清楚地了解架构的意图: * 模块 starter:如上所述 = 仅引导应用程序,因此取决于其他所有内容 * 模块 咖啡:用于订购尴尬变体咖啡的休息服务(香草,生姜,......) *模块收银员:用于支付订单的休息服务模块咖啡和收银员不需要了解彼此,从架构的角度来看,将它们分开是一种很好的做法。 Multi-Module 允许将它们作为整体保持在一个项目中,使它们更易于处理(部署和开发)。 你不需要应用 spring-boot 插件来使用 MockMvc 进行测试。该插件仅用于最终打包为独立的 jar(或 war)。您也不需要带有 SpringBootApplication 注释的类来测试您的 Spring 控制器。我可能根本不依赖starter
模块,而只是单独测试模块的功能。然后对应用程序模块 (starter
) 或单个单独模块中的所有模块进行全面的集成测试以进行测试。这并不是说你的方式是错误的,我只是以前从未见过这样的做法:)以上是关于无法集成测试 gradle 多模块 Spring-Boot-Application的主要内容,如果未能解决你的问题,请参考以下文章
使用 Spring 在多模块 Maven 项目中进行集成测试
使用 spring boot gradle 插件无法使用依赖管理执行 junit5 测试
Gradle kotlin Springboot多模块导致无法引用kotlin的类文件(BootJar)
Gradle kotlin Springboot多模块导致无法引用kotlin的类文件(BootJar)
线程“main”中的异常 java.lang.ClassNotFoundException - Spring Boot,多模块 gradle 项目