多虚拟机测试

支持同时在多个 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.sbt 或project/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 任务类似于常规任务:test、testOnly和run,但在多 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

3. object SampleMultiJvmNode1 {
4. def main(args: Array[String]) {
5. println("Hello from node 1")
6. }
7. }

9. object SampleMultiJvmNode2 {
10. def main(args: Array[String]) {
11. println("Hello from node 2")
12. }
13. }

15. object SampleMultiJvmNode3 {
16. def main(args: Array[String]) {
17. println("Hello from node 3")
18. }
19. }

当你在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

3. import org.scalatest.WordSpec
4. import org.scalatest.matchers.MustMatchers

6. class SpecMultiJvmNode1 extends WordSpec with MustMatchers {
7. "A node" should {
8. "be able to say hello" in {
9. val message = "Hello from node 1"
10. message must be("Hello from node 1")
11. }
12. }
13. }

15. class SpecMultiJvmNode2 extends WordSpec with MustMatchers {
16. "A node" should {
17. "be able to say hello" in {
18. val message = "Hello from node 2"
19. message must be("Hello from node 2")
20. }
21. }
22. }

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

多节点添加

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


英文原文链接:Multi JVM Testing.