我想使用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"))
大多数测试要并行执行,但MyDatabaseTest1
和MyDatabaseTest2
不会与另一个同时运行。
我可以使用specs2吗?
答案 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分叉测试的工作方式截然不同。此分支和许多其他测试功能不适用于分叉测试。