多JVM测试

注:本节未经校验,如有问题欢迎提issue

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

安装程序

多JVM测试是 sbt 插件,你可以在 http://github.com/typesafehub/sbt-multi-jvm 找到。

你可以作为一个插件添加它,在 project/plugins.sbt 添加以下内容:

  1. addSbtPlugin ("com.typesafe.sbt"%"sbt 多 jvm"%"0.3.8"

然后,你可以通过在build.sbtproject/Build.scala包含MultiJvm和设置添加多JVM 测试。请注意 MultiJvm 测试源代码位于 src/multi-jvm/...而不是在src/test/...

下面是使用 MultiJvm 插件的 sbt 0.13 下的 build.sbt 文件示例:

  1. import com.typesafe.sbt.SbtMultiJvm
  2. import com.typesafe.sbt.SbtMultiJvm.MultiJvmKeys.MultiJvm
  3. val akkaVersion = "2.3.6"
  4. val project = Project(
  5. id = "akka-sample-multi-node-scala",
  6. base = file("."),
  7. settings = Project.defaultSettings ++ SbtMultiJvm.multiJvmSettings ++ Seq(
  8. name := "akka-sample-multi-node-scala",
  9. version := "2.3.6",
  10. scalaVersion := "2.10.4",
  11. libraryDependencies ++= Seq(
  12. "com.typesafe.akka" %% "akka-remote" % akkaVersion,
  13. "com.typesafe.akka" %% "akka-multi-node-testkit" % akkaVersion,
  14. "org.scalatest" %% "scalatest" % "2.0" % "test"),
  15. // make sure that MultiJvm test are compiled by the default test compilation
  16. compile in MultiJvm <<= (compile in MultiJvm) triggeredBy (compile in Test),
  17. // disable parallel tests
  18. parallelExecution in Test := false,
  19. // make sure that MultiJvm tests are executed by the default test target,
  20. // and combine the results from ordinary test and multi-jvm tests
  21. executeTests in Test <<= (executeTests in Test, executeTests in MultiJvm) map {
  22. case (testResults, multiNodeResults) =>
  23. val overall =
  24. if (testResults.overall.id < multiNodeResults.overall.id)
  25. multiNodeResults.overall
  26. else
  27. testResults.overall
  28. Tests.Output(overall,
  29. testResults.events ++ multiNodeResults.events,
  30. testResults.summaries ++ multiNodeResults.summaries)
  31. }
  32. )
  33. ) configs (MultiJvm)

你可以为分支 Jvm 指定 JVM 选项:

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

运行测试

多JVM任务是类似于正常的任务:test, test-onlyrun,但在multi-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

使用test-only运行单个测试:

  1. multi-jvm:test-only akka.remote.RandomRoutedRemoteActor

可以列出多个测试名称来运行多个特定的测试。使用sbt的 tab 键可以很容易地完成测试的名称。

也可以通过在测试名称后和--包括这些选项,来指定 JVM 选项为test-only。举个例子:

  1. multi-jvm:test-only 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: ...

更改默认设置

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

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

你可以更改MultiJvm标识符。例如,使用 multiJvmMarker 设置更改它为ClusterTest

  1. multiJvmMarker in MultiJvm := "ClusterTest"

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

JVM 实例配置

你可以为每个生成的 Jvm定义特定 JVM 选项。通过创建一个以节点的名字命名的带有.opts后缀的文件,把它们放在测试的同一个目录中。

例如,为SampleMultiJvmNode1提供 JVM 选项-Dakka.remote.port=9991-Xmx256m,让我们创建三个 *.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 测试。要这样做,要如上所述使用相同的命名约定,但创建 ScalaTest 套件,而不是对象的main方法。你需要在类路径上有 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:test-only sample.Spec来执行这些测试。

多节点添加

此外对SbtMultiJvm插件有一些补充,以适应实验模块一节中描述的多节点测试