基于Maven Surefire配置构建含测试依赖的可执行Uber Jar
解决方案:构建包含Cucumber测试运行器的可执行Uber Jar
核心思路
你的场景需要打包主应用代码、子模块编译产物、测试类、测试依赖四类资源,普通插件要么不支持测试类打包,要么容易触发类冲突(比如Spring Boot自动配置类、Cucumber插件定义)。下面提供两种经过验证的方案,优先适配Spring环境的方案。
方案一:Spring Boot Maven Plugin打包测试代码(推荐)
如果测试运行器基于@SpringBootTest,直接用Spring Boot插件的测试打包能力,它会自动处理Spring环境的依赖和类路径:
- 在主模块
pom.xml中配置插件:
<build> <plugins> <!-- 保留原有主应用打包配置,新增测试打包执行 --> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <executions> <execution> <id>repackage-tests</id> <goals> <goal>repackage</goal> </goals> <configuration> <classifier>tests</classifier> <!-- 替换为你的Cucumber测试运行器全类名 --> <mainClass>com.example.CucumberTestRunner</mainClass> <includes> <include> <groupId>${project.groupId}</groupId> <artifactId>*</artifactId> <classifier>tests</classifier> </include> </includes> </configuration> </execution> </executions> </plugin> <!-- 确保子模块测试类被编译为test-jar供主模块引用 --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> <executions> <execution> <goals> <goal>test-jar</goal> </goals> </execution> </executions> </plugin> </plugins> </build>
- 执行打包命令:
mvn clean package
打包完成后会生成[项目名]-tests.jar,直接运行:
java -jar [项目名]-tests.jar
方案二:Shade插件+依赖插件手动处理
如果不依赖Spring Boot插件,手动管控测试类和依赖的打包逻辑:
- 配置
maven-dependency-plugin导出测试依赖到临时目录:
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-dependency-plugin</artifactId> <executions> <execution> <id>copy-test-deps</id> <phase>prepare-package</phase> <goals> <goal>copy-dependencies</goal> </goals> <configuration> <outputDirectory>${project.build.directory}/test-libs</outputDirectory> <includeScope>test</includeScope> </configuration> </execution> </executions> </plugin>
- 配置
maven-shade-plugin合并资源、处理冲突:
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <version>3.4.1</version> <executions> <execution> <phase>package</phase> <goals> <goal>shade</goal> </goals> <configuration> <transformers> <!-- 指定测试运行器为主类 --> <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"> <mainClass>com.example.CucumberTestRunner</mainClass> </transformer> <!-- 合并Spring自动配置文件,避免加载失败 --> <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer"> <resource>META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports</resource> </transformer> <!-- 合并Cucumber插件定义,避免步骤丢失 --> <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer"> <resource>META-INF/services/io.cucumber.core.plugin.Plugin</resource> </transformer> </transformers> <!-- 排除签名文件,避免打包报错 --> <filters> <filter> <artifact>*:*</artifact> <excludes> <exclude>META-INF/*.SF</exclude> <exclude>META-INF/*.DSA</exclude> <exclude>META-INF/*.RSA</exclude> </excludes> </filter> </filters> <!-- 包含主应用、子模块、测试依赖的类 --> <artifactSet> <includes> <include>${project.groupId}:</include> <include>io.cucumber:*</include> <include>org.testng:*</include> <include>org.springframework.boot:spring-boot-test*</include> </includes> </artifactSet> <!-- 引入临时目录的测试依赖 --> <additionalClasspathElements> <additionalClasspathElement>${project.build.directory}/test-libs</additionalClasspathElement> </additionalClasspathElements> </configuration> </execution> </executions> </plugin>
- 执行打包命令:
mvn clean package
生成的Jar即可直接运行。
常见问题排查
- 类找不到:检查Shade插件的
artifactSet是否包含所有子模块,确保子模块的test-jar被主模块依赖。 - Cucumber步骤定义丢失:确认测试类被纳入打包范围,可在Shade配置中添加
<include>${project.build.testOutputDirectory}</include>。 - Spring上下文加载失败:检查
AutoConfiguration.imports文件是否被正确合并,确保Spring Boot自动配置类能被扫描到。 - 多线程失效:保持原有TestNG/Cucumber的多线程配置,运行Jar时可通过参数指定:
java -jar xxx.jar -Dcucumber.execution.parallel.enabled=true
内容的提问来源于stack exchange,提问作者Paulo Oliveira
相关产品推荐
相关产品推荐

