我们的集成测试和启动/停止延迟的不同环境存在问题。
所以,我们希望在所有集成测试之前运行所有环境依赖项,并最终关闭。 我们不能只使用 docker,因为我们使用 GuiceApplication(从代码开始)、EmbeddedKafka(从代码开始)和 WireMock(从代码开始)。 :)
我们使用 scala 作为主要语言,使用 Specs2 作为测试库。我发现我们可以创建一个规范,在所有代码之前/之后添加以设置环境,并覆盖代表测试的
is
方法。我们可以通过将其他一些规格加入一个
override def is = Seq(new First, new Second)
.map(_.is)
.foldLeft(Fragments.empty) { case (l, r) => l.append(r.fragments)}
但我想自动将规格收集到
is.
中我看到一个SpecificationFinder
特征与findSpecifications
和specifications,
等方法,但我不能让他们返回一个非空列表。我们有一个名为“集成”的根目录,我们在其中存储所有需要的规格。
也许有人已经实现了对测试的搜索。看起来在sbt测试任务中使用了这些方法,但我没有找到一种方法来重用它
根据您使用的 specs2 版本,该问题有两个答案。
specs2-4.x(完整示例在这里)
有了这个版本,您可以使用
SpecificationsFinder
收集规范,并将它们聚合为一个大规范,前面有一个 step
,后面有一个 step
来启动和停止共享服务:
import org.specs2._
import org.specs2.specification.core._
import org.specs2.control._
import org.specs2.io._
import runner._
import user.integration.database._
class IntegrationSpec extends Specification { def is = sequential ^ s2"""
${step(db.start)}
Integration specifications
$integration
${step(db.shutdown)}
"""
def integration =
Fragments.foreach(specifications) { specification =>
s2"""
${specification.is.header.name} ${specification.is.fragments}
$p
"""
}
val specifications: List[SpecificationStructure] = SpecificationsFinder.findSpecifications(
// change this pattern if the specifications must be found in specific directories, or with specific names
glob = "**/*.scala",
// this pattern detects the name of a specification class inside a scala file
pattern = "(.*Spec)\\s*extends\\s*.*",
// this additional filter can be used to filter specifications names
// in this case we avoid infinite recursive execution
filter = { (name: String) => !name.endsWith("IntegrationSpec") },
// this is the base directory where specifications must be searched
basePath = DirectoryPath.unsafe(new java.io.File("src/test/scala").getAbsolutePath),
verbose = true).runOption.getOrElse(Nil)
}
specs2-5.x(完整示例这里)
随着 specs2 的最新版本,引入了“全局资源”的概念,以便每个单独的规范都可以扩展
Resource[R]
特征(其中 R
是全局资源,这里是一个带有 Database
的示例):
trait StartDatabase(using ec: ExecutionContext) extends Resource[Database]:
override def resourceKey: Option[String] =
Some("shared database")
def acquire: Future[Database] =
Future.successful(Database().start)
def release(db: Database): Execution =
Future { db.shutdown; true }
在那种情况下,之前
steps
中使用的IntegrationSpec
不再需要了。