推荐的Akka Props样式仅在单元测试中抛出IllegalArgumentException

时间:2014-02-18 20:22:12

标签: unit-testing scala akka scala-2.10

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

我声明两个简单的Greeter Actors,一个在内部,一个在规范之外,然后以两种不同的方式为每一个获取ActorRef - 一次使用不推荐使用的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

1 个答案:

答案 0 :(得分:2)

您在这里面对的是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 <: 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")