创建包含 SBT 项目+子项目中所有测试的程序集 jar
Create assembly jar that contains all tests in SBT project+subprojects
我有一个有趣的问题,我基本上需要创建一个 .jar
(加上所有类路径依赖项),其中包含 SBT 项目(加上它的任何子项目)的所有测试。我的想法是,我可以使用 java -jar
运行 jar,所有测试都将执行。
我听说这可以用 sbt-assembly 做,但你必须手动 运行 assembly
为你拥有的每个 sbt 子项目(每个都有自己的 .jars
) 理想情况下,我只想 运行 一个命令,它为您碰巧拥有的每个 sbt root+sub 项目中的每个测试生成一个巨大的 .jar
(以同样的方式,如果您 运行 test
在带有子项目的 sbt 项目中它将 运行 测试所有内容)。
我们目前使用的测试框架是 specs2,但我不确定这是否有影响。
有人知道这是否可行吗?
不支持导出测试运行ner
sbt 1.3.x 没有这个功能。定义的测试与测试框架(如 Specs2)和 sbt 的构建提供的 运行ner 一起执行,它也反射性地发现您定义的测试(例如,哪个 class 扩展了 Spec2 的测试特征?)。理论上,我们已经有了您需要的大部分内容,因为 Test / fork := true
创建了一个名为 ForkMain
的程序,并且 运行 在另一个 JVM 中进行了测试。缺少的是调度您定义的测试。
使用 specs2.run 运行ner
谢天谢地,Specs2 提供了一个开箱即用的 运行ner,名为 specs2.run
(参见 In the shell):
scala -cp ... specs2.run com.company.SpecName [argument1 argument2 ...]
所以基本上你需要知道的是:
- 你的class路径
- 您定义的测试的完全限定名称列表
以下是使用 sbt 获取它们的方法:
> print Test/fullClasspath
* Attributed(/private/tmp/specs-runner/target/scala-2.13/test-classes)
* Attributed(/private/tmp/specs-runner/target/scala-2.13/classes)
* Attributed(/Users/eed3si9n/.coursier/cache/v1/https/repo1.maven.org/maven2/org/scala-lang/modules/scala-xml_2.13/1.2.0/scala-xml_2.13-1.2.0.jar)
...
> print Test/definedTests
* Test foo.HelloWorldSpec : subclass(false, org.specs2.specification.core.SpecificationStructure)
我们可以从 sbt shell 中练习 specs2.run
运行ner 如下:
> Test/runMain specs2.run foo.HelloWorldSpec
跨子项目汇总
跨子项目聚合测试需要一些思考。与其创建一个巨大的组装球,不如推荐以下内容。创建一个虚拟子项目 testAgg
,然后将所有 Test/externalDependencyClasspath
和 Test/packageBin
收集到它的 target/dist
中。然后,您可以根据需要获取所有 JAR 和 运行 java -jar ...
。
如何以编程方式进行?参见 Getting values from multiple scopes。
lazy val collectJars = taskKey[Seq[File]]("")
lazy val collectDefinedTests = taskKey[Seq[String]]("")
lazy val testFilter = ScopeFilter(inAnyProject, inConfigurations(Test))
lazy val testAgg = (project in file("testAgg"))
.settings(
name := "testAgg",
publish / skip := true,
collectJars := {
val cps = externalDependencyClasspath.all(testFilter).value.flatten.distinct
val pkgs = packageBin.all(testFilter).value
cps.map(_.data) ++ pkgs
},
collectDefinedTests := {
val dts = definedTests.all(testFilter).value.flatten
dts.map(_.name)
},
Test / test := {
val jars = collectJars.value
val tests = collectDefinedTests.value
sys.process.Process(s"""java -cp ${jars.mkString(":")} specs2.run ${tests.mkString(" ")}""").!
}
)
这个运行是这样的:
> testAgg/test
[info] HelloWorldSpec
[info]
[info] The 'Hello world' string should
[info] + contain 11 characters
[info] + start with 'Hello'
[info] + end with 'world'
[info]
[info]
[info] Total for specification HelloWorldSpec
[info] Finished in 124 ms
3 examples, 0 failure, 0 error
[info] testAgg / Test / test 1s
如果你真的想要,你可能可以从 collectDefinedTests
生成源代码,使 testAgg
依赖于所有子项目的 Test
配置,并尝试制作一个巨大的程序集球, 但我会留给 reader :)
作为练习
我有一个有趣的问题,我基本上需要创建一个 .jar
(加上所有类路径依赖项),其中包含 SBT 项目(加上它的任何子项目)的所有测试。我的想法是,我可以使用 java -jar
运行 jar,所有测试都将执行。
我听说这可以用 sbt-assembly 做,但你必须手动 运行 assembly
为你拥有的每个 sbt 子项目(每个都有自己的 .jars
) 理想情况下,我只想 运行 一个命令,它为您碰巧拥有的每个 sbt root+sub 项目中的每个测试生成一个巨大的 .jar
(以同样的方式,如果您 运行 test
在带有子项目的 sbt 项目中它将 运行 测试所有内容)。
我们目前使用的测试框架是 specs2,但我不确定这是否有影响。
有人知道这是否可行吗?
不支持导出测试运行ner
sbt 1.3.x 没有这个功能。定义的测试与测试框架(如 Specs2)和 sbt 的构建提供的 运行ner 一起执行,它也反射性地发现您定义的测试(例如,哪个 class 扩展了 Spec2 的测试特征?)。理论上,我们已经有了您需要的大部分内容,因为 Test / fork := true
创建了一个名为 ForkMain
的程序,并且 运行 在另一个 JVM 中进行了测试。缺少的是调度您定义的测试。
使用 specs2.run 运行ner
谢天谢地,Specs2 提供了一个开箱即用的 运行ner,名为 specs2.run
(参见 In the shell):
scala -cp ... specs2.run com.company.SpecName [argument1 argument2 ...]
所以基本上你需要知道的是:
- 你的class路径
- 您定义的测试的完全限定名称列表
以下是使用 sbt 获取它们的方法:
> print Test/fullClasspath
* Attributed(/private/tmp/specs-runner/target/scala-2.13/test-classes)
* Attributed(/private/tmp/specs-runner/target/scala-2.13/classes)
* Attributed(/Users/eed3si9n/.coursier/cache/v1/https/repo1.maven.org/maven2/org/scala-lang/modules/scala-xml_2.13/1.2.0/scala-xml_2.13-1.2.0.jar)
...
> print Test/definedTests
* Test foo.HelloWorldSpec : subclass(false, org.specs2.specification.core.SpecificationStructure)
我们可以从 sbt shell 中练习 specs2.run
运行ner 如下:
> Test/runMain specs2.run foo.HelloWorldSpec
跨子项目汇总
跨子项目聚合测试需要一些思考。与其创建一个巨大的组装球,不如推荐以下内容。创建一个虚拟子项目 testAgg
,然后将所有 Test/externalDependencyClasspath
和 Test/packageBin
收集到它的 target/dist
中。然后,您可以根据需要获取所有 JAR 和 运行 java -jar ...
。
如何以编程方式进行?参见 Getting values from multiple scopes。
lazy val collectJars = taskKey[Seq[File]]("")
lazy val collectDefinedTests = taskKey[Seq[String]]("")
lazy val testFilter = ScopeFilter(inAnyProject, inConfigurations(Test))
lazy val testAgg = (project in file("testAgg"))
.settings(
name := "testAgg",
publish / skip := true,
collectJars := {
val cps = externalDependencyClasspath.all(testFilter).value.flatten.distinct
val pkgs = packageBin.all(testFilter).value
cps.map(_.data) ++ pkgs
},
collectDefinedTests := {
val dts = definedTests.all(testFilter).value.flatten
dts.map(_.name)
},
Test / test := {
val jars = collectJars.value
val tests = collectDefinedTests.value
sys.process.Process(s"""java -cp ${jars.mkString(":")} specs2.run ${tests.mkString(" ")}""").!
}
)
这个运行是这样的:
> testAgg/test
[info] HelloWorldSpec
[info]
[info] The 'Hello world' string should
[info] + contain 11 characters
[info] + start with 'Hello'
[info] + end with 'world'
[info]
[info]
[info] Total for specification HelloWorldSpec
[info] Finished in 124 ms
3 examples, 0 failure, 0 error
[info] testAgg / Test / test 1s
如果你真的想要,你可能可以从 collectDefinedTests
生成源代码,使 testAgg
依赖于所有子项目的 Test
配置,并尝试制作一个巨大的程序集球, 但我会留给 reader :)