【问题标题】:Recommended Akka Props style throws IllegalArgumentException only inside unit test推荐的 Akka Props 样式仅在单元测试中抛出 IllegalArgumentException
【发布时间】:2014-03-18 20:07:51
【问题描述】:

请参阅下面的单元测试。在通过 system.actorOf 实例化时,在单元测试本身内部和外部定义的 Actor 类似乎表现不同,但仅在使用 Akka 文档中推荐的 Props 样式时(第 67 页,Akka Scala 文档的第 3.1 节 Props,版本 2.2 .3)。

我声明了两个简单的 Greeter Actor,一个在规范内,一个在规范外,然后以两种不同的方式为每个人获取 ActorRefs - 一次使用不推荐使用的 Props 样式,一次使用推荐的 Props 样式。只有第 [4] 行会抛出 IllegalArgumentException。

任何想法可能会发生什么?感谢您的帮助!

(注意:使用 FunSpec 也会出现同样的问题,因此 WordSpec、MustMatchers 似乎不是一个因素)

import org.junit.runner.RunWith
import org.scalatest.WordSpec
import org.scalatest.matchers.MustMatchers
import akka.actor.ActorSystem
import akka.actor.Props
import org.scalatest.junit.JUnitRunner
import akka.actor.Actor

class MyGreeter extends Actor {
  def receive = {
    case _ => println("greetings!")
  }
}

@RunWith(classOf[JUnitRunner])
class HelloAkkaTest extends WordSpec with MustMatchers {

  class MyOtherGreeter extends Actor {
    def receive = {
      case _ => println("greetings!")
    }
  }

  "Greeter" must {
    "greet" in {
      val system = ActorSystem()
      system.actorOf(Props[MyGreeter], "greeter")       // [1] Works
      system.actorOf(Props(new Greeter))            // [2] Works
      system.actorOf(Props(new MyOtherGreeter))     // [3] Works
      system.actorOf(Props[MyOtherGreeter], "other")    // [4] Fails!
    }
  }
}

我将 scalatest 2.10-2.0-RC3 与 scala 2.10.2 和 akka 2.10-2.3.0-RC2 一起使用

【问题讨论】:

  • 你应该使用 Akka 测试工具包来测试 actor ;)。它提供了对演员和演员系统的良好控制。使用这种方法,您将在测试它时遇到很多麻烦。您的测试可能希望在您的参与者系统终止之前终止,并且参与者可能不会及时创建/终止。这是一个麻烦的世界相信我:)。
  • 感谢 Aleksey 我一直在深入研究 TestKit,感谢 Derek Wyatt 的一本非常有用的 Akka Concurrency 书籍,我更了解您所说的以这种风格进行测试的内容。我的问题是这种行为与 TestKit 的行为相同

标签: unit-testing scala akka scala-2.10


【解决方案1】:

您在这里遇到的是 scala 和嵌套类的一个有趣细节。当你有一个像

这样的结构时
class Foo {
  class Bar
}

那么内部类 Bar 将绑定到 Foo 的特定实例,这意味着您不能在此实例之外实例化它。

scala> new Foo
res5: Foo = Foo@5b2cef50

scala> new res5.Bar
res6: res5.Bar = Foo$Bar@64f8b658

scala> new Foo#Bar
  <console>:12: error: Foo is not a legal prefix for a constructor
          new Foo#Bar
                  ^

Props.apply[A &lt;: Actor] 隐式检索ClassTag[A] 的实例,然后尝试通过反射调用构造函数。那么我们来看看Foo#Bar的构造函数:

scala> classOf[Foo#Bar].getConstructors
res9: Array[java.lang.reflect.Constructor[_]] = Array(public Foo$Bar(Foo))

如您所见,它需要Foo 的实例作为参数。那么我们该如何解决呢?

我的建议是只参加测试课程之外的课程。有两种可能,或者直接放在包下,作为你的其他类,或者放在测试类的同伴中。

解决此问题的另一种方法是将测试类的引用传递给Props

system.actorOf(Props(classOf[MyOtherGreeter], this), "other")

【讨论】:

  • 如果你不使用外部指针,你也许可以传递 null
  • 感谢 Drexin,提供了解决方法(将其移到外部)以及帮助我​​理解嵌套类的潜在问题以及它如何变成期望引用外部类实例的构造函数。
猜你喜欢
  • 2012-03-24
  • 2017-12-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-11-09
  • 1970-01-01
  • 2020-02-19
相关资源
最近更新 更多