【问题标题】:Use SBT tags to control specs2 test concurrency使用 SBT 标签控制 specs2 测试并发
【发布时间】:2016-04-14 04:35:14
【问题描述】:

我想使用 SBT 标签来控制我的一些规范的并发性。

例如,我不希望同时运行超过 1 个使用数据库的测试。

使用 ScalaTest,我会这样做

@TagAnnotation("database")
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
public @interface DatabaseTest { }

@DatabaseTest
class MyDatabaseTest1 ...

@DatabaseTest
class MyDatabaseTest2 ...

然后在 build.sbt 中,

concurrentRestrictions in Global += exclusiveGroups(Tag("database"))

大多数测试要并行执行,但MyDatabaseTest1MyDatabaseTest2 不会与另一个同时运行。

我可以用 specs2 做到这一点吗?

【问题讨论】:

  • 您是否尝试使用相同的标签来注释您的规范?我实际上不知道您可以使用它来降低规范的并发级别。请注意,除非您使用 sequential 参数,否则每个规范都会保持并发。
  • @Eric, er, TagAnnotation 是一个 ScalaTest 注释,(我假设)由 ScalaTest 运行器使用并暴露给 SBT。我应该说清楚的。
  • 是的,规范中示例的执行由 specs2 控制,而不是 SBT。我发现这很容易控制,因为所有示例都可以在一个文件中看到。
  • 好的,我知道了。尚不支持此功能。在 specs2 中执行此操作的一种方法是创建一个包含指向数据库规范的链接的父规范并按顺序执行该规范。缺点是您必须维护此父规范并在有一些规范时添加新规范。所以更好的方法是让你等我实现它:-)
  • 我在3.7.3-20160413201225-0d1765e 中添加了对标签的缺失支持,但采用的是specs2 已经知道的标签形式:etorreborre.github.io/specs2/guide/SPECS2-3.7.3/…。我试图观察 sbt 的“无并发”行为,但什么也看不到(但我看到标签已找到)。

标签: concurrency sbt specs2


【解决方案1】:

我自己添加了功能。 (内置支持问题:https://github.com/etorreborre/specs2/issues/470

src/test/java/test/Tag.scala

首先定义一个要使用的注解。 (我相信这只能在 Java 中完成。)

package test;

import java.lang.annotation.*;

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
public @interface Tag {
    String name();
}

src/test/scala/test/TaggingFramework.scala

然后定义一个sbt.testing.Framework 的实现,它包装了Framework 并为注释添加标签。 (注意:这取决于org.scala-sbt:test-interface。如果您已经在提取specs2,它应该已经存在。)

package test

import java.lang.annotation.Annotation
import sbt.testing._
import scala.util.Try

class TaggingFramework(framework: Framework) extends Framework {
  def fingerprints(): Array[Fingerprint] = framework.fingerprints()

  def name = s"TaggingFramework(${framework.name})"

  def runner(args: Array[String], remoteArgs: Array[String], testClassLoader: ClassLoader) = {
    val runner = framework.runner(args, remoteArgs, testClassLoader)
    println(runner)
    new Runner {
      def args() = runner.args()

      def done() = runner.done()

      def remoteArgs = runner.remoteArgs()

      def tasks(taskDefs: Array[TaskDef]) = runner.tasks(taskDefs).map { task =>
        new Task {
          def execute(eventHandler: EventHandler, loggers: Array[Logger]) = task.execute(eventHandler, loggers)
          def taskDef = task.taskDef
          def tags = task.tags ++ {
            val fingerprint = taskDef.fingerprint
            Try {
              val isModule = fingerprint.getClass.getMethod("isModule").invoke(fingerprint).asInstanceOf[Boolean]
              val className = taskDef.fullyQualifiedName + (if (isModule) "$" else "")
              println(testClassLoader.loadClass(className).getAnnotationsByType(classOf[Tag]).map(_.name).toSeq)
              testClassLoader.loadClass(className).getAnnotationsByType(classOf[Tag]).map(_.name)
            }.getOrElse(Array.empty)
          }
        }
      }
    }
  }
}

project/TaggingTestFramework.scala

然后在构建定义中,定义sbt.TestFrameworkTaggingTestFramework 子类。这将加载TaggingFramework(如果存在)。否则,它只是使用原始框架。

import sbt.TestFramework
import sbt.testing._
import scala.language.existentials
import scala.util.Try

class TaggingTestFramework(testFramework: TestFramework) extends TestFramework() {
  override def create(loader: ClassLoader, log: sbt.Logger) = testFramework.create(loader, log).map { framework =>
    Try(
      Class.forName("test.TaggingFramework", true, loader).asInstanceOf[Class[Framework]]
        .getConstructor(classOf[Framework]).newInstance(framework)
    ).getOrElse(framework)
  }

  override def toString = s"TaggingTestFramework($testFramework)"
}

build.sbt

并包装testFrameworks

testFrameworks := testFrameworks.value.map(new TaggingTestFramework(_))

这应该主要适用于任何 Scala 或 Java 框架,包括 specs2。


src/test/scala/example/MySpec.scala

最后,要使用为测试任务添加标签,只需将注释添加到类。

import org.specs2.mutable.Specification
import test.Tag

@Tag(name = "database")
class MySpec extends Specification ...

注意 1:这目前不适用于继承。

注意 2:SBT 分叉测试的工作方式非常不同。此功能和许多其他测试功能不适用于分叉测试。

【讨论】:

    猜你喜欢
    • 2016-02-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多