多虚拟机测试

支持同时在多个 JVM 中运行应用程序(具有main方法的对象)和ScalaTest测试。对于多个系统相互通信的集成测试很有用。

安装程序

多 JVM 测试是一个sbt插件,可以在 https://github.com/sbt/sbt-multi-jvm 中找到。要在项目中配置它,应执行以下步骤:

  1. 将它作为插件添加到你的project/plugins.sbt中:
  1. addSbtPlugin("com.typesafe.sbt" % "sbt-multi-jvm" % "0.4.0")
  1. 通过启用MultiJvmPlugin并设置MultiJvm配置,将多 JVM 测试添加到build.sbtproject/Build.scala
  1. lazy val root = (project in file("."))
  2. .enablePlugins(MultiJvmPlugin)
  3. .configs(MultiJvm)

请注意,默认情况下,MultiJvm测试源位于src/multi-jvm/...,而不是位于src/test/....

下面是一个使用sbt-multi-jvm插件的「示例项目」。

运行测试

多 JVM 任务类似于常规任务:testtestOnlyrun,但在多 JVM 配置下。

因此,在 Akka 中,要运行akka-remote项目使用中的所有多 JVM 测试(在sbt提示下):

  1. akka-remote-tests/multi-jvm:test

或者可以先切换到akka-remote-tests项目,然后运行测试:

  1. project akka-remote-tests
  2. multi-jvm:test

要运行单个测试,请使用testOnly

  1. multi-jvm:testOnly akka.remote.RandomRoutedRemoteActor

可以列出多个测试名称以运行多个特定测试。sbt中的制表符使完成测试名称变得容易。

也可以使用testOnly指定 JVM 选项,方法是在测试名称和--之后包含这些选项。例如:

  1. multi-jvm:testOnly akka.remote.RandomRoutedRemoteActor -- -Dsome.option=something

创建应用程序测试

通过命名约定,可以发现并组合这些测试。MultiJvm测试源位于src/multi-jvm/...。使用以下模式命名测试:

  1. {TestName}MultiJvm{NodeName}

也就是说,每个测试的名称中间都有MultiJvm。前面的部分将测试/应用程序分组在一起,使用一个将一起运行的TestName。后面的部分NodeName是每个分叉的 JVM 的一个区别名称。

因此,要创建一个名为Sample的 3 节点测试,可以创建三个应用程序,如下所示:

  1. package sample
  2. object SampleMultiJvmNode1 {
  3. def main(args: Array[String]) {
  4. println("Hello from node 1")
  5. }
  6. }
  7. object SampleMultiJvmNode2 {
  8. def main(args: Array[String]) {
  9. println("Hello from node 2")
  10. }
  11. }
  12. object SampleMultiJvmNode3 {
  13. def main(args: Array[String]) {
  14. println("Hello from node 3")
  15. }
  16. }

当你在sbt提示下调用multi-jvm:run sample.Sample时,将生成三个 JVM,每个节点一个。它看起来像这样:

  1. > multi-jvm:run sample.Sample
  2. ...
  3. [info] * sample.Sample
  4. [JVM-1] Hello from node 1
  5. [JVM-2] Hello from node 2
  6. [JVM-3] Hello from node 3
  7. [success] Total time: ...

更改默认值

你可以为分叉(forked)的 JVM 指定 JVM 选项:

  1. jvmOptions in MultiJvm := Seq("-Xmx256M")

你可以通过向项目中添加以下配置来更改多 JVM 测试源目录的名称:

  1. unmanagedSourceDirectories in MultiJvm :=
  2. Seq(baseDirectory(_ / "src/some_directory_here")).join.value

你可以更改MultiJvm标识符。例如,要将其更改为ClusterTest,请使用multiJvmMarker设置:

  1. multiJvmMarker in MultiJvm := "ClusterTest"

你的测试现在应该命名为{TestName}ClusterTest{NodeName}

JVM 实例的配置

你可以为每个生成的 JVM 定义特定的 JVM 选项。通过在测试中创建一个后缀为.opts的文件,并将其放在与测试相同的目录中,可以做到这一点。

例如,要将 JVM 选项-Dakka.remote.port=9991-Xmx256m送到SampleMultiJvmNode1,让我们创建三个*.opts文件并将这些选项添加到它们中。用空格分隔多个选项。

  • SampleMultiJvmNode1.opts
  1. -Dakka.remote.port=9991 -Xmx256m
  • SampleMultiJvmNode2.opts
  1. -Dakka.remote.port=9992 -Xmx256m
  • SampleMultiJvmNode3.opts
  1. -Dakka.remote.port=9993 -Xmx256m

ScalaTest

还支持创建ScalaTest测试,而不是应用程序。要做到这一点,请使用与上面相同的命名约定,但要使用main方法创建ScalaTest套件,而不是对象。你需要在classpath上有ScalaTest。这里有一个类似于上面的例子,但是使用ScalaTest

  1. package sample
  2. import org.scalatest.WordSpec
  3. import org.scalatest.matchers.MustMatchers
  4. class SpecMultiJvmNode1 extends WordSpec with MustMatchers {
  5. "A node" should {
  6. "be able to say hello" in {
  7. val message = "Hello from node 1"
  8. message must be("Hello from node 1")
  9. }
  10. }
  11. }
  12. class SpecMultiJvmNode2 extends WordSpec with MustMatchers {
  13. "A node" should {
  14. "be able to say hello" in {
  15. val message = "Hello from node 2"
  16. message must be("Hello from node 2")
  17. }
  18. }
  19. }

为了运行这些测试,你可以在sbt提示下调用multi-jvm:testOnly sample.Spec

多节点添加

还对SbtMultiJvm插件进行了一些添加,以适应「可能更改」模块的「多节点测试」,如该部分所述。


英文原文链接Multi JVM Testing.