代码之家  ›  专栏  ›  技术社区  ›  Eugene Yokota

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

  •  6
  • Eugene Yokota  · 技术社区  · 7 年前

    这个问题是马丁·格罗茨克提出的 Twitter .

    他想写一个任务(或命令,我想)可以:

    1. 第一次跑步 test 如果失败了,继续 testOnly
    2. 在生成中跨多个子项目聚合

    有效模拟Bash:

    $ sbt test || sbt testQuick
    

    其动机是两次运行失败的测试来解决片状测试。

    1 回复  |  直到 7 年前
        1
  •  8
  •   Eugene Yokota    7 年前

    项目/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 . 你可以在上面进行模式匹配来获得值,但我们并不真正需要它。

    我用它来定义另一种选择 测试 调用的任务 testNoFail .

    临时插件

    接下来,我们要 测试不失败 在多项目生成中工作。向所有子项目注入设置的一种方法是定义触发 AutoPlugin 在里面 project/*.scala .

      override def requires = plugins.JvmPlugin
      override def trigger = allRequirements
    

    指挥部组成

    如果你想让sbt做点什么 然后 做些别的事情,可能一个自然的方法就是使用命令。这类似于人类把东西连续地输入外壳。

    命令可以用分号组成 ; .

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

    这是可能的,因为我们可以安全地运行 testQuick task 不管以前的测试状态如何。

    另见 Sequencing How to 序列,用于对事物进行排序的其他方法。

    如何使用这个

    运行:

    > testExtraShot
    

    在sbt外壳内。这将运行 测试不失败 然后 快速测试 .

    附录:处理条件延续

    注意,我通过运行 快速测试 不管怎样。这是有可能实现的,但它有点先进。

    一元连续

    我们可以定义一个首先正常运行的任务 测试 ,然后根据返回的 结果 值,更改 下一个 任务。在sbt中,可以使用 dynamic task .

    我们通常尝试避免这种组合,因为它防止任务引擎并行化并发任务,但当我们需要if-then执行某些操作时,它很方便。

    project/TestExtraShotPlugin.scala替代版本

    以下实现了定义动态任务的即席插件:

    import sbt._
    import Keys._
    
    object TestExtraShotPlugin extends AutoPlugin {
      override def requires = plugins.JvmPlugin
      override def trigger = allRequirements
      object autoImport {
        val testExtraShot = taskKey[Unit]("test then testQuick only on failure")
      }
      import autoImport._
    
      override def projectSettings = {
        testExtraShot := (Def.taskDyn {
          val t = (Test / test).result.value
          if (t.toEither.isLeft) (Test / testQuick).toTask("")
          else
            Def.task {
              val s = streams.value
              s.log.info("ok!")
            }
        }).value
      }
    }
    
    推荐文章