使用SBT标记来控制specs2测试并发

时间:2016-04-12 22:31:18

标签: concurrency sbt specs2

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

例如,我不想要使用数据库同时运行的多个测试。

使用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吗?

1 个答案:

答案 0 :(得分:0)

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

<强>的src /测试/ JAVA /测试/ Tag.scala

首先定义要使用的注释。 (我相信这只能用Java完成。)

package test;

import java.lang.annotation.*;

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

<强>的src /测试/阶/测试/ 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)
          }
        }
      }
    }
  }
}

<强>项目/ TaggingTestFramework.scala

然后在构建定义中,定义TaggingTestFramework的{​​{1}}子类。这将加载sbt.TestFramework(如果存在)。否则,它只使用原始框架。

TaggingFramework

<强> build.sbt

并打包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)" }

testFrameworks

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

<强>的src /测试/阶/示例/ MySpec.scala

最后,要使用向测试任务添加标记,只需将注释添加到类中即可。

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

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

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