如何通过Spark Submit运行Maven测试及Spark应用Scalatest流水线测试?
刚好之前处理过类似的场景,给你梳理下可行的方案,先直接说核心结论:不能直接用spark-submit的--class参数来运行Scalatest测试,因为Scalatest是基于测试框架的生命周期运行的(比如初始化测试环境、执行断言、校验结果),而spark-submit只是用来启动带main方法的Spark应用,不会自动识别和执行测试用例。下面是几种靠谱的实现思路:
方案一:用构建工具先跑测试,再提交应用(最推荐)
这是行业里最常规的做法,毕竟Scalatest本来就是和sbt/maven这类构建工具深度集成的:
- 如果用sbt:先执行
sbt test跑所有测试,等测试全过了再提交应用。你可以把这两步写成一个简单的bash脚本,自动判断测试结果:
#!/bin/bash # 先运行所有Scalatest测试 sbt test # 检查测试是否通过($?是上一条命令的退出码,0代表成功) if [ $? -eq 0 ]; then echo "所有测试通过,开始提交Spark应用..." spark-submit --class com.your.package.YourMainClass --master yarn ./target/scala-2.12/your-app.jar else echo "测试失败,终止应用提交" exit 1 fi
- 如果用maven:逻辑类似,先执行
mvn test,测试通过后用mvn package打包,再用spark-submit提交打包好的jar包就行。
方案二:写一个测试入口类,用spark-submit触发测试+应用
如果你的场景必须用spark-submit来触发测试(比如某些CI环境的限制),可以手动写一个带main方法的类,调用Scalatest的运行器来执行测试,通过后再启动主应用:
- 先调整项目依赖,把Scalatest的scope从
test改成compile(这样打包后会包含测试库),比如sbt里的依赖配置:
libraryDependencies += "org.scalatest" %% "scalatest" % "3.2.15" % "compile"
- 写一个测试入口类,比如:
import org.scalatest.runner.Runner import org.scalatest.tools.RunnerArgs object SparkTestRunner { def main(args: Array[String]): Unit = { // 这里指定你要运行的测试类全限定名 val targetTests = Seq("com.your.package.DataTransformTest") // 配置测试运行参数,输出结果到控制台 val runnerArgs = RunnerArgs( testClasses = targetTests, reporter = Some(org.scalatest.tools.ConsoleReporter()), failIfNoTests = true ) // 执行测试,获取结果 val testsPassed = Runner.run(runnerArgs) // 如果测试失败,直接退出;通过则启动主应用 if (!testsPassed) { println("测试未通过,终止应用启动") System.exit(1) } else { println("所有测试通过,启动主应用...") com.your.package.YourMainClass.main(args) } } }
- 然后用spark-submit运行这个入口类:
spark-submit --class com.your.package.SparkTestRunner --master local[*] ./target/scala-2.12/your-app.jar
⚠️ 注意:这种方式会把测试代码和应用代码打包在一起,生产环境不建议这么做,只适合测试/CI场景使用;另外测试里的SparkContext要和主应用的做好隔离,避免资源冲突。
方案三:CI流水线拆分测试和部署阶段
如果是在CI/CD流水线(比如Jenkins、GitLab CI)里,直接把测试和应用提交拆成两个独立的阶段:
- 第一阶段:拉取代码 → 执行
sbt test/mvn test→ 测试不通过则终止流水线 - 第二阶段:测试通过后 → 打包应用 → 用spark-submit提交到集群
这种方式更清晰,测试和部署完全解耦,也符合DevOps的最佳实践。
最后再补充下为什么直接用spark-submit跑测试不行:Scalatest的测试类一般是继承FlatSpec/FunSuite这类特质,它们没有main方法,spark-submit无法直接运行;就算你给测试类加了main,也需要自己手动处理测试的执行逻辑,不如用上面的方案来得规范。
内容的提问来源于stack exchange,提问作者user4046073
相关产品推荐
相关产品推荐

