如何在集成测试中使用sbt-assembly生成的Uber Jar并挂载到Docker Testcontainer?
方案完全可行
这是跨SBT模块进行集成测试的典型场景,核心思路是让测试模块依赖生成Uber Jar的模块的构建产物,再通过Testcontainers将Jar挂载到容器中运行。以下是具体实现步骤:
1. 配置SBT模块间的依赖与产物路径
- 在生成Uber Jar的模块(假设为
service-module)的build.sbt中,指定Jar的输出路径为多模块共享目录,方便测试模块访问:
assemblyOutputPath := file((ThisBuild / baseDirectory).value / "target" / "shared-assemblies" / "service-assembly.jar")
- 在测试模块(假设为
integration-test-module)的build.sbt中,添加对service-module的构建依赖,确保测试任务执行前先生成Uber Jar:
lazy val integrationTestModule = (project in file("integration-test-module")) .settings( // 让集成测试任务依赖service-module的assembly任务 IntegrationTest / test := (IntegrationTest / test).dependsOn(serviceModule / assembly).value ) .dependsOn(serviceModule) .enablePlugins(IntegrationTestPlugin)
2. 在集成测试中用Testcontainers挂载Jar
使用Scala版Testcontainers封装(或原生Java库),将生成的Uber Jar挂载到容器中并启动:
import org.testcontainers.containers.GenericContainer import org.testcontainers.utility.DockerImageName import scala.util.Try class ServiceIntegrationTest extends AnyFunSuite { test("verify service runs in container") { // 动态获取Uber Jar路径 val serviceJar = (serviceModule / assemblyOutputPath).value val container = new GenericContainer(DockerImageName.parse("openjdk:17")) // 挂载本地Jar到容器内指定路径 .withFileSystemBind(serviceJar.getAbsolutePath, "/app/service.jar") // 启动Jar的命令 .withCommand("java", "-jar", "/app/service.jar") // 暴露服务端口(按需配置) .withExposedPorts(8080) // 启动容器并执行测试逻辑 container.start() Try { val servicePort = container.getMappedPort(8080) // 这里编写集成测试断言,比如调用服务接口验证可用性 assert(/* 自定义测试条件 */) } finally { container.stop() } } }
关键注意事项
- 路径正确性:尽量使用SBT内置的路径变量(如
baseDirectory、assemblyOutputPath)动态获取Jar路径,避免硬编码相对路径导致的跨环境问题。 - JDK版本匹配:容器使用的JDK镜像版本必须与Uber Jar编译时的目标JDK版本一致,否则会出现运行时兼容性错误。
- 任务顺序:确保测试模块的
it:test任务明确依赖目标模块的assembly任务,防止测试执行时Jar还未生成。
内容的提问来源于stack exchange,提问作者senjin.hajrulahovic
相关产品推荐
相关产品推荐

