多虚拟机测试
支持同时在多个 JVM 中运行应用程序(具有main
方法的对象)和ScalaTest
测试。对于多个系统相互通信的集成测试很有用。
安装程序
多 JVM 测试是一个sbt
插件,可以在 https://github.com/sbt/sbt-multi-jvm 中找到。要在项目中配置它,应执行以下步骤:
- 将它作为插件添加到你的
project/plugins.sbt
中:
addSbtPlugin("com.typesafe.sbt" % "sbt-multi-jvm" % "0.4.0")
- 通过启用
MultiJvmPlugin
并设置MultiJvm
配置,将多 JVM 测试添加到build.sbt
或project/Build.scala
。
lazy val root = (project in file("."))
.enablePlugins(MultiJvmPlugin)
.configs(MultiJvm)
请注意,默认情况下,MultiJvm
测试源位于src/multi-jvm/...
,而不是位于src/test/....
。
下面是一个使用sbt-multi-jvm
插件的「示例项目」。
运行测试
多 JVM 任务类似于常规任务:test
、testOnly
和run
,但在多 JVM 配置下。
因此,在 Akka 中,要运行akka-remote
项目使用中的所有多 JVM 测试(在sbt
提示下):
akka-remote-tests/multi-jvm:test
或者可以先切换到akka-remote-tests
项目,然后运行测试:
project akka-remote-tests
multi-jvm:test
要运行单个测试,请使用testOnly
:
multi-jvm:testOnly akka.remote.RandomRoutedRemoteActor
可以列出多个测试名称以运行多个特定测试。sbt
中的制表符使完成测试名称变得容易。
也可以使用testOnly
指定 JVM 选项,方法是在测试名称和--
之后包含这些选项。例如:
multi-jvm:testOnly akka.remote.RandomRoutedRemoteActor -- -Dsome.option=something
创建应用程序测试
通过命名约定,可以发现并组合这些测试。MultiJvm
测试源位于src/multi-jvm/...
。使用以下模式命名测试:
{TestName}MultiJvm{NodeName}
也就是说,每个测试的名称中间都有MultiJvm
。前面的部分将测试/应用程序分组在一起,使用一个将一起运行的TestName
。后面的部分NodeName
是每个分叉的 JVM 的一个区别名称。
因此,要创建一个名为Sample
的 3 节点测试,可以创建三个应用程序,如下所示:
package sample
object SampleMultiJvmNode1 {
def main(args: Array[String]) {
println("Hello from node 1")
}
}
object SampleMultiJvmNode2 {
def main(args: Array[String]) {
println("Hello from node 2")
}
}
object SampleMultiJvmNode3 {
def main(args: Array[String]) {
println("Hello from node 3")
}
}
当你在sbt
提示下调用multi-jvm:run sample.Sample
时,将生成三个 JVM,每个节点一个。它看起来像这样:
> multi-jvm:run sample.Sample
...
[info] * sample.Sample
[JVM-1] Hello from node 1
[JVM-2] Hello from node 2
[JVM-3] Hello from node 3
[success] Total time: ...
更改默认值
你可以为分叉(forked
)的 JVM 指定 JVM 选项:
jvmOptions in MultiJvm := Seq("-Xmx256M")
你可以通过向项目中添加以下配置来更改多 JVM 测试源目录的名称:
unmanagedSourceDirectories in MultiJvm :=
Seq(baseDirectory(_ / "src/some_directory_here")).join.value
你可以更改MultiJvm
标识符。例如,要将其更改为ClusterTest
,请使用multiJvmMarker
设置:
multiJvmMarker in MultiJvm := "ClusterTest"
你的测试现在应该命名为{TestName}ClusterTest{NodeName}
。
JVM 实例的配置
你可以为每个生成的 JVM 定义特定的 JVM 选项。通过在测试中创建一个后缀为.opts
的文件,并将其放在与测试相同的目录中,可以做到这一点。
例如,要将 JVM 选项-Dakka.remote.port=9991
和-Xmx256m
送到SampleMultiJvmNode1
,让我们创建三个*.opts
文件并将这些选项添加到它们中。用空格分隔多个选项。
SampleMultiJvmNode1.opts
:
-Dakka.remote.port=9991 -Xmx256m
SampleMultiJvmNode2.opts
:
-Dakka.remote.port=9992 -Xmx256m
SampleMultiJvmNode3.opts
:
-Dakka.remote.port=9993 -Xmx256m
ScalaTest
还支持创建ScalaTest
测试,而不是应用程序。要做到这一点,请使用与上面相同的命名约定,但要使用main
方法创建ScalaTest
套件,而不是对象。你需要在classpath
上有ScalaTest
。这里有一个类似于上面的例子,但是使用ScalaTest
:
package sample
import org.scalatest.WordSpec
import org.scalatest.matchers.MustMatchers
class SpecMultiJvmNode1 extends WordSpec with MustMatchers {
"A node" should {
"be able to say hello" in {
val message = "Hello from node 1"
message must be("Hello from node 1")
}
}
}
class SpecMultiJvmNode2 extends WordSpec with MustMatchers {
"A node" should {
"be able to say hello" in {
val message = "Hello from node 2"
message must be("Hello from node 2")
}
}
}
为了运行这些测试,你可以在sbt
提示下调用multi-jvm:testOnly sample.Spec
。
多节点添加
还对SbtMultiJvm
插件进行了一些添加,以适应「可能更改」模块的「多节点测试」,如该部分所述。
英文原文链接:Multi JVM Testing.