sbt:如何编写仅在测试失败时才运行testQuick的任务?

时间:2018-08-04 19:05:36

标签: scala sbt

这个问题来自Twitter上的马丁·格罗茨克(Martin Grotzke)。

他想写一个可以做的任务(或者说一个命令):

  1. 首先运行test,如果失败,请继续执行testOnly
  2. 聚集一个建筑中的多个子项目

有效地模拟Bash:

$ sbt test || sbt testQuick

动机是运行两次失败的测试以解决不稳定的测试。

1 个答案:

答案 0 :(得分:8)

project / TestExtraShotPlugin.scala

如果您想获得快速解答,则可以使用以下代码来实现两次运行测试行为。

import sbt._
import Keys._

object TestExtraShotPlugin extends AutoPlugin {
  override def requires = plugins.JvmPlugin
  override def trigger = allRequirements
  object autoImport {
    val testNoFail = taskKey[Unit]("test but don't fail")
  }
  import autoImport._

  override def buildSettings = {
    addCommandAlias("testExtraShot", ";testNoFail;testQuick")
  }

  override def projectSettings = {
    Test / testNoFail := (Test / test).result.value
  }
}

如果您想了解更多信息,请继续阅读。

错误处理

首先,我们需要停止test停止任务执行。文档的Tasks页中介绍了任务的错误处理。但是要点是您打电话给.result.value。您可以对其进行模式匹配以获得值,但是我们在这里实际上并不需要它。

我正在使用它来定义另一个名为test的{​​{1}}任务。

Ad-hoc插件

接下来,我们希望testNoFail在多项目构建中工作。将设置注入所有子项目的一种方法是在testNoFail中定义触发的AutoPlugin

project/*.scala

命令组成

如果您想让sbt 然后做其他事情,那么一种自然的方法就是使用命令。这类似于人类向外壳中连续输入内容。

可以使用分号 override def requires = plugins.JvmPlugin override def trigger = allRequirements 来编写命令。

;

之所以可行,是因为无论测试以前的状态如何,我们都可以安全地运行testQuick task

另请参见Sequencing How to系列,以了解其他对事物进行排序的方法。

如何使用

运行:

  override def buildSettings = {
    addCommandAlias("testExtraShot", ";testNoFail;testQuick")
  }
在sbt shell内

。这将先运行> testExtraShot ,然后运行testNoFail

附录:处理条件延续

请注意,无论如何,我通过运行testQuick绕过了Martin最初的“万一测试失败”的规范。可以实现这一点,但是要先进一些。

单音延续

我们可以定义一个首先运行正常testQuick的任务,然后根据返回的 result 值,更改 next 任务的继续。在sbt中,可以使用dynamic task来实现这种单子连续性。

我们通常试图避免这种组合,因为它阻止了任务引擎并行化并发任务,但是当我们需要if-then-do-something时它很方便。

project / TestExtraShotPlugin.scala替代版本

以下实现了一个临时插件,该插件定义了一个动态任务:

test