【问题标题】:SBT: how to modify it:test with a task that calls the original test task?SBT:如何修改它:使用调用原始测试任务的任务进行测试?
【发布时间】:2013-11-23 00:28:13
【问题描述】:

在下面我的 Build.scala 文件的 sn-p 中,itTestWithService 任务在运行集成测试之前和之后启动测试服务器。

我想将此itTestWithService 任务附加到it:test 键。但是怎么做呢?

  lazy val mohs =
    Project(id = "mohs", base = file("."))
     .settings (
        // I'd like the following but it creates a cycle that fails at runtime:
        // test in IntegrationTest <<= testWithService   
        itTestWithService <<= testWithService
      )

  val itTestWithService = taskKey[Unit]("run integration test with background server")

  /** run integration tests against a test server.  (the server is started before the tests and stopped after the tests) */
  lazy val testWithService = Def.task {
    val log = streams.value.log
    val launched = (start in testService).value
    launched match {
      case Success(_) =>
        testAndStop.value
      case Failure(e) =>
        val stack = e.getStackTrace().mkString("\n")
        log.error(s"failed to start test server: $e \n ${stack}")
    }
  }

  /** run integration tests and then stop the test server */
  lazy val testAndStop = Def.taskDyn {
    val _ = (test in IntegrationTest).value
    stop in testService
  }

【问题讨论】:

    标签: scala sbt


    【解决方案1】:

    在相关的github issue discussion 中,Josh 建议了一种针对我询问的特定情况的方法(覆盖它:使用调用原始测试任务的任务进行测试)。

    该方法通过重新实现测试任务来工作。我不知道是否有更通用的方法可以访问任务的原始版本。 (比这个更通用的方法会是更好的答案!)

    以下是如何重新实现 it:test 任务:

      /** run integration tests (just like it:test does, but explicitly so we can overwrite the it:test key */
      lazy val itTestTask: Initialize[Task[Unit]] = Def.taskDyn {
        for {
          results <- (executeTests in IntegrationTest)
        } yield { Tests.showResults(streams.value.log, results, "test missing?") }
      }
    

    这是复合集成测试任务(从原始问题略微演变而来,但该版本也应该可以工作):

      /** run integration tests against a test server.  (the server is started before the tests and stopped after the tests) */
      lazy val testWithServiceTask = Def.taskDyn {
        (start in testService).value match {
          case Success(_) =>
            testAndStop
          case Failure(e) =>
            val stack = e.getStackTrace().mkString("\n")
            streams.value.log.error(s"failed to start test server: $e \n ${stack}")
            emptyTask
        }
      }
    
      /** run integration tests and then stop the test server */
      lazy val testAndStop = Def.taskDyn {
        SbtUtil.sequence(itTestTask, stop in testService)
      }
    
      val emptyTask = Def.task {}
    

    现在将我们内置的复合任务插入 it:test 键不会创建循环:

      lazy val mohs =
        Project(id = "mohs", base = file("."))
          .settings (
            test in IntegrationTest <<= testWithServiceTask,
          )
    

    【讨论】:

      【解决方案2】:

      您可以在 build.scala 中添加自定义测试标签。这是我的一个项目的示例代码。请记住,您不必将其绑定到它:test。你可以随意命名它。

      lazy val AcceptanceTest = config("acc") extend(Test)
      
        lazy val Kernel = Project(
          id = "kernel",
          base = file("."),
          settings = defaultSettings ++ AkkaKernelPlugin.distSettings ++ Seq(
              libraryDependencies ++= Dependencies.Kernel,
              distJvmOptions in Dist := "-Xms256M -Xmx2048M",
              outputDirectory in Dist := file("target/dist"),
              distMainClass in Dist := "akka.kernel.Main system.SystemKernel"
            )
        ).configs(AcceptanceTest)
         .settings(inConfig(AcceptanceTest)(Defaults.testTasks): _*)
         .settings(testOptions in AcceptanceTest := Seq(Tests.Argument("-n",
           "AcceptanceTest"), Tests.Argument("-oD")))
      

      只需注意顶部的惰性 val 和 .configs 部分。

      使用该设置,当我键入 acc:test 时,它会使用 AcceptanceTestTag 运行所有测试。您可以将服务器作为测试套件调用的一部分启动。甚至可以通过需要服务器和不需要服务器来标记测试,以便在您的套件变大并需要更长的运行时间时将它们分开。

      编辑:添加以响应 cmets。

      要标记测试,请创建这样的标记

      import org.scalatest.Tag
      object AcceptanceTest extends Tag("AcceptanceTest")
      

      然后把它放在你的测试中......

      it("should allow any actor to subscribe to any channel", AcceptanceTest) {
      

      这与上述相同的构建设置相呼应。当我调用 acc:test 时,只会运行带有 That 标签的测试。

      对于您的问题,我想到的是我在相同情况下使用的解决方案。现在,您正在 build.scala 中进行工作。我不确定是否可以按照您所说的去做......但我所做的事情是一样的,但有点不同。我有一个特点,我将所有需要流浪服务器的测试都混入其中。我将使用它的测试标记为 VagrantTest。

      它就像一个单例。如果一项或多项测试需要它,它会启动。但它只会启动一个,所有测试都使用它。

      您可以尝试做同样的事情,但在配置文件中覆盖它:test。代替上面示例中的“acc”,输入“it”。如果这不是您想要的,可能需要看看是否有其他人出现。

      所以,基本上当我调用它:test 时,它会访问运行带有 IntegrationTest 测试标签的所有测试(以及带有 VagrantTest 和其他一些测试标签的测试)。因此,所有运行时间较长的服务器测试都不会运行那么多(花费太长时间)。

      【讨论】:

      • 啊,谢谢你的回答。你如何标记你的测试?这听起来是个有趣的想法。
      • 我了解我可以使用新密钥或不同范围的密钥。原始问题在同一配置中使用了新键,而您的示例使用了不同范围内的键。但是这里的问题是是否可以在相同的配置范围(它)中使用相同的键(测试)。我认为,如果我的用户可以重用他们从其他构建中知道的关于如何运行集成测试的知识,而不必为此记住新的东西,那就太好了。
      • 忘了说,每个测试可以有多个标签。
      猜你喜欢
      • 2015-01-08
      • 2018-02-11
      • 2017-11-26
      • 2014-05-23
      • 2016-08-13
      • 2022-01-12
      • 2017-06-16
      • 2014-09-06
      • 2015-08-27
      相关资源
      最近更新 更多