在 SBT 中使用“sbt testOnly”从 jar 中运行测试?

Posted

技术标签:

【中文标题】在 SBT 中使用“sbt testOnly”从 jar 中运行测试?【英文标题】:Running tests from jar with "sbt testOnly" in SBT? 【发布时间】:2014-03-31 04:56:38 【问题描述】:

作为 CI 设置的一部分,第一步是使用 SBT dist 创建一个包/jar。以下步骤是使用dist-created jar 运行单元、集成和功能测试。

SBT 可以做到这一点吗?

通常我使用sbt testOnly "Unit.*",但这适用于项目的上下文。当已经有一个 jar 时,我找不到任何说明如何执行此操作的文档。

我正在使用 ScalaTest,我知道有一个跑步者可以使用 http://www.scalatest.org/user_guide/using_the_runner。但如果可能的话,使用 SBT 会更简单。

例如,我正在寻找这样的东西:

sbt testOnly "Unit.* -jar myjar.jar"

当我使用以下内容时,我的测试是否会包含在 jar 中:

sbt dist

?

编辑

    我创建了一个新文件夹

    我添加了build.sbt,内容如下:

    name := "abc"
    
    version := "1.0-SNAPSHOT"
    
    scalaVersion := "2.10.0"
    

    我添加了lib 文件夹并将我的测试jar 复制到其中

    我跑了sbt testOnly Unit.*

    找不到任何测试

编辑 2

我尝试使用以下“正确”的 SBT 文件:

name := "ihs2tests"

version := "1.0-SNAPSHOT"

scalaVersion := "2.10.0"

unmanagedBase in Test := new java.io.File(".")

并将test.jar 移动到项目的根目录中。同样,没有找到任何测试。

【问题讨论】:

这应该可以帮助您入门:***.com/a/16409096/2197460. 测试代码通常不包含在 dist jar 中,但 @DaveSwartz 的链接可能对此有所帮助。 sbt test:dist 怎么样?这不包括(测试)dist jar 中的测试吗? 【参考方案1】:

通常我使用 sbt testOnly "Unit.*",但这适用于项目的上下文。当已经有一个 jar 时,我找不到任何说明如何执行此操作的文档。

SBT 中的test-family 任务(以testOnly 为例)与通过sbt.inc.Analysis 实例返回已编译文件列表的compile 任务一起使用。我不知道如何修改它并将更改后的分析实例注入testOnly,因此它知道我要运行的测试存在。

我正在提出另一种解决方案 - 一个技巧

将测试类打包到一个带有test:package任务的jar中,如下所示:

[test-lib]> test:package
[info] Updating file:/Users/jacek/sandbox/so/test-lib/test-lib...
[info] Resolving org.fusesource.jansi#jansi;1.4 ...
[info] Done updating.
[info] Compiling 1 Scala source to /Users/jacek/sandbox/so/test-lib/target/scala-2.10/test-classes...
[info] Packaging /Users/jacek/sandbox/so/test-lib/target/scala-2.10/test-lib_2.10-0.1-SNAPSHOT-tests.jar ...
[info] Done packaging.
[success] Total time: 9 s, completed Mar 4, 2014 11:34:13 PM

当您拥有测试 jar 时,您可以在命令行上执行测试框架没有 SBT(我假设您使用 ScalaTest 给定scalatest 标签,但我将使用 Specs2)。阅读测试框架的文档以了解如何执行此操作,对于 Specs2,它是 specs2.run,如 Console output 中所述。

从测试 jar 执行测试需要定义一个正确的 CLASSPATH,这可能会也可能不会很容易正确。这就是 SBT 可以提供很大帮助的地方 - 管理依赖关系,从而管理 CLASSPATH。

创建另一个 SBT 项目并将测试 jar 保存在 lib 子目录中以将其放在 CLASSPATH 中(如 Unmanaged dependencies 中所述)。

lib 中的依赖关系在所有类路径上(用于编译、测试、运行和控制台)。

添加一个示例build.sbt,您可以在其中将测试框架定义为项目的依赖项。对于 Specs2 如下(我使用了the Specs2 home page 中描述的默认配置):

libraryDependencies += "org.specs2" %% "specs2" % "2.3.8" % "test"

scalacOptions in Test ++= Seq("-Yrangepos")

诀窍是执行测试框架的主类,例如specs2.run 用于 Specs2,就好像该类是在命令行上执行的一样。 SBT 帮助test:runMain

[my-another-project]> test:runMain specs2.run HelloWorldSpec
[info] Running specs2.run HelloWorldSpec
HelloWorldSpec

The 'Hello world' string should
+ contain 11 characters
+ start with 'Hello'
+ end with 'world'

Total for specification HelloWorldSpec
Finished in 62 ms
3 examples, 0 failure, 0 error

Exception: sbt.TrapExitSecurityException thrown from the UncaughtExceptionHandler in thread "run-main-0"
[success] Total time: 5 s, completed Mar 4, 2014 11:15:14 PM

不要担心这个Exception,因为它来自 SBT,它从 Specs2(测试执行后)捕获 exit,所以 SBT 仍然存在。

【讨论】:

我将 build.sbt 和 tests.jar 复制到了一个新项目中,但它试图再次编译它,所以很遗憾这不起作用 再试一次!【参考方案2】:

如果没有任何额外/手动设置,SBT 似乎无法读取 jar 文件 - 我可能错了,但我在文档中没有找到任何内容。所以我尝试了这样的方法来简化任务:

unzip some-test.jar

java -jar sbt-launch.jar \
  'set scalaSource in Test := new java.io.File(".")' \
  'set fullClasspath in Test += Attributed.blank(file("."))' \
  'test'

这运行没有错误,但没有找到测试。

如果我添加 'set includeFilter in (Test, unmanagedSources) := "*Suite*.class"' 来强制它查找测试,它显然会失败,因为它需要 *.scala 文件,而不是编译后的 *.class 文件。

我不是 SBT 专家,但我认为这必须接近解决方案。必须有一种方法可以通过编程方式从 jar 路径中读取所有文件,然后告诉测试框架使用 *.class 文件。

此时使用 Scalatest 测试运行器或使用项目从 sbt 运行测试似乎更合理。

如果您想深入了解,请查看 SBT 源代码和默认的 sbt shell 脚本,该脚本在运行 sbt 启动器 jar 之前会进行大量设置。

【讨论】:

以上是关于在 SBT 中使用“sbt testOnly”从 jar 中运行测试?的主要内容,如果未能解决你的问题,请参考以下文章

使用 Scala 从 SBT 获取堆栈跟踪

使用 Scala IDE 中的 SBT

从 Eclipse 运行 SBT 任务

在 Play 2.3.x 应用程序中使用 sbt-rjs 从 WebJars 优化 JS

您可以从 sbt 提示符注入编译器插件吗?

需要从我在我的 sbt 插件中使用的插件中提供一个 SettingKey