2013-08-20 57 views
10

我遇到了一个演员延伸Stash的问题,当在简单的ActorSystem中使用actorOf实例化它时,它工作得很好。现在我真的想在我的程序中使用它们之前为我的存储演员编写一些测试。但是我无法想出一个在我的测试套件中使用TestActorRef和这个actor的方法。测试Akka演员mixin藏着TestActorRef

,工程的代码看起来是这样的:

import akka.actor.{Stash, Actor, ActorSystem, Props} 
import com.typesafe.config.ConfigFactory 

object StashTest { 
    val config = ConfigFactory.parseString(
    """ 
     |akka.actor.default-mailbox { 
     | mailbox-type = "akka.dispatch.UnboundedDequeBasedMailbox" 
     |} 
    """.stripMargin) 
} 

class StashTestActor extends Stash { 

    def receive: Actor.Receive = { 
    case "unstash" => 
     unstashAll() 
     context become print 
    case msg => stash() 
    } 

    def print: Actor.Receive = { 
    case msg => println(s"Unstashed message: $msg") 
    } 
} 

val system = ActorSystem("stashSystem", StashTest.config) 
val ref = system.actorOf(Props[StashTestActor]) 

ref ! "stash me" 
ref ! "blah" 
ref ! "unstash" 

它打印

Unstashed message: stash me 

Unstashed message: blah 

但是,如果我尝试写一个WordSpec测试这个演员,这给我留下了一些讨厌的例外,我可以弄清楚他们希望我在代码中改变什么。

测试类看起来像这样

import akka.testkit.{TestActorRef, TestKit} 
import akka.actor.{Stash, Actor, ActorSystem} 
import org.scalatest.{WordSpecLike, MustMatchers} 
import com.typesafe.config.ConfigFactory 


class StashTestActor extends Stash { 

    def receive: Actor.Receive = { 
    case "unstash" => 
     unstashAll() 
     context become print 
    case msg => stash() 
    } 

    def print: Actor.Receive = { 
    case msg => println(s"Unstashed message: $msg") 
    } 
} 


class StashTest extends TestKit(ActorSystem("testSystem", StashTest.config)) 
with WordSpecLike 
with MustMatchers { 

    "A simple stashing actor" must { 
    val actorRef = TestActorRef[StashTestActor] 

    "stash messages" in { 
     actorRef ! "stash me!" 
    } 

    "unstash all messages" in { 
     actorRef ! "unstash" 
    } 
    } 
} 

object StashTest { 
    val config = ConfigFactory.parseString(
    """ 
     |akka.actor.default-mailbox { 
     | mailbox-type = "akka.dispatch.UnboundedDequeBasedMailbox" 
     |} 
    """.stripMargin) 
} 

运行测试时,我获得以下属于TestActorRef的实例化时抛出的异常。

[ERROR] [08/20/2013 14:19:40.765] [testSystem-akka.actor.default-dispatcher-3] [akka://testSystem/user/$$a] Could not instantiate Actor 
Make sure Actor is NOT defined inside a class/trait, 
if so put it outside the class/trait, f.e. in a companion object, 
OR try to change: 'actorOf(Props[MyActor]' to 'actorOf(Props(new MyActor)'. 
akka.actor.ActorInitializationException: exception during creation 
    at akka.actor.ActorInitializationException$.apply(Actor.scala:218) 
    at akka.actor.ActorCell.create(ActorCell.scala:578) 
    at akka.actor.ActorCell.invokeAll$1(ActorCell.scala:425) 
    at akka.actor.ActorCell.systemInvoke(ActorCell.scala:447) 
    at akka.dispatch.Mailbox.processAllSystemMessages(Mailbox.scala:262) 
    at akka.testkit.CallingThreadDispatcher.process$1(CallingThreadDispatcher.scala:244) 
    at akka.testkit.CallingThreadDispatcher.runQueue(CallingThreadDispatcher.scala:284) 
    at akka.testkit.CallingThreadDispatcher.register(CallingThreadDispatcher.scala:153) 
    at akka.dispatch.MessageDispatcher.attach(AbstractDispatcher.scala:133) 
    at akka.actor.dungeon.Dispatch$class.start(Dispatch.scala:84) 
    at akka.actor.ActorCell.start(ActorCell.scala:338) 
    at akka.testkit.TestActorRef.<init>(TestActorRef.scala:50) 
    at akka.testkit.TestActorRef$.apply(TestActorRef.scala:141) 
    at akka.testkit.TestActorRef$.apply(TestActorRef.scala:137) 
    at akka.testkit.TestActorRef$.apply(TestActorRef.scala:146) 
    at akka.testkit.TestActorRef$.apply(TestActorRef.scala:144) 
    at stashActorTest.StashTest$$anonfun$1.apply$mcV$sp(StashTestActor.scala:29) 
    at stashActorTest.StashTest$$anonfun$1.apply(StashTestActor.scala:28) 
    at stashActorTest.StashTest$$anonfun$1.apply(StashTestActor.scala:28) 
    at org.scalatest.SuperEngine.registerNestedBranch(Engine.scala:613) 
    at org.scalatest.WordSpecLike$class.org$scalatest$WordSpecLike$$registerBranch(WordSpecLike.scala:120) 
    at org.scalatest.WordSpecLike$$anon$2.apply(WordSpecLike.scala:851) 
    at org.scalatest.words.MustVerb$StringMustWrapperForVerb$class.must(MustVerb.scala:189) 
    at org.scalatest.matchers.MustMatchers$StringMustWrapper.must(MustMatchers.scala:6167) 
    at stashActorTest.StashTest.<init>(StashTestActor.scala:28) 
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) 
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57) 
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) 
    at java.lang.reflect.Constructor.newInstance(Constructor.java:526) 
    at java.lang.Class.newInstance(Class.java:374) 
    at org.scalatest.tools.Framework$ScalaTestTask.execute(Framework.scala:444) 
    at sbt.TestRunner.runTest$1(TestFramework.scala:84) 
    at sbt.TestRunner.run(TestFramework.scala:94) 
    at sbt.TestFramework$$anon$2$$anonfun$$init$$1$$anonfun$apply$8.apply(TestFramework.scala:224) 
    at sbt.TestFramework$$anon$2$$anonfun$$init$$1$$anonfun$apply$8.apply(TestFramework.scala:224) 
    at sbt.TestFramework$.sbt$TestFramework$$withContextLoader(TestFramework.scala:212) 
    at sbt.TestFramework$$anon$2$$anonfun$$init$$1.apply(TestFramework.scala:224) 
    at sbt.TestFramework$$anon$2$$anonfun$$init$$1.apply(TestFramework.scala:224) 
    at sbt.TestFunction.apply(TestFramework.scala:229) 
    at sbt.Tests$$anonfun$7.apply(Tests.scala:196) 
    at sbt.Tests$$anonfun$7.apply(Tests.scala:196) 
    at sbt.std.Transform$$anon$3$$anonfun$apply$2.apply(System.scala:45) 
    at sbt.std.Transform$$anon$3$$anonfun$apply$2.apply(System.scala:45) 
    at sbt.std.Transform$$anon$4.work(System.scala:64) 
    at sbt.Execute$$anonfun$submit$1$$anonfun$apply$1.apply(Execute.scala:237) 
    at sbt.Execute$$anonfun$submit$1$$anonfun$apply$1.apply(Execute.scala:237) 
    at sbt.ErrorHandling$.wideConvert(ErrorHandling.scala:18) 
    at sbt.Execute.work(Execute.scala:244) 
    at sbt.Execute$$anonfun$submit$1.apply(Execute.scala:237) 
    at sbt.Execute$$anonfun$submit$1.apply(Execute.scala:237) 
    at sbt.ConcurrentRestrictions$$anon$4$$anonfun$1.apply(ConcurrentRestrictions.scala:160) 
    at sbt.CompletionService$$anon$2.call(CompletionService.scala:30) 
    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:334) 
    at java.util.concurrent.FutureTask.run(FutureTask.java:166) 
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471) 
    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:334) 
    at java.util.concurrent.FutureTask.run(FutureTask.java:166) 
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) 
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) 
    at java.lang.Thread.run(Thread.java:724) 
Caused by: akka.actor.ActorInitializationException: Could not instantiate Actor 
Make sure Actor is NOT defined inside a class/trait, 
if so put it outside the class/trait, f.e. in a companion object, 
OR try to change: 'actorOf(Props[MyActor]' to 'actorOf(Props(new MyActor)'. 
    at akka.actor.ActorInitializationException$.apply(Actor.scala:218) 
    at akka.testkit.TestActorRef$$anonfun$apply$2$$anonfun$apply$1.applyOrElse(TestActorRef.scala:148) 
    at akka.testkit.TestActorRef$$anonfun$apply$2$$anonfun$apply$1.applyOrElse(TestActorRef.scala:147) 
    at scala.runtime.AbstractPartialFunction.apply(AbstractPartialFunction.scala:33) 
    at scala.util.Failure$$anonfun$recover$1.apply(Try.scala:185) 
    at scala.util.Try$.apply(Try.scala:161) 
    at scala.util.Failure.recover(Try.scala:185) 
    at akka.testkit.TestActorRef$$anonfun$apply$2.apply(TestActorRef.scala:147) 
    at akka.testkit.TestActorRef$$anonfun$apply$2.apply(TestActorRef.scala:153) 
    at akka.actor.CreatorFunctionConsumer.produce(Props.scala:369) 
    at akka.actor.Props.newActor(Props.scala:323) 
    at akka.actor.ActorCell.newActor(ActorCell.scala:534) 
    at akka.actor.ActorCell.create(ActorCell.scala:560) 
    ... 58 more 
Caused by: java.lang.NullPointerException 
    at akka.actor.UnrestrictedStash$class.$init$(Stash.scala:82) 
    at stashActorTest.StashTestActor.<init>(StashTestActor.scala:9) 
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) 
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57) 
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) 
    at java.lang.reflect.Constructor.newInstance(Constructor.java:526) 
    at akka.actor.ReflectiveDynamicAccess$$anonfun$createInstanceFor$2.apply(DynamicAccess.scala:78) 
    at scala.util.Try$.apply(Try.scala:161) 
    at akka.actor.ReflectiveDynamicAccess.createInstanceFor(DynamicAccess.scala:73) 
    ... 64 more 

我对使用TestActorRefs和不扩展Stash的actor有任何问题。所以我不知道这是一个配置错误还是我错过的其他东西。

回答

2

我能够与藏匿测试的演员是这样的:

val actor = TestActorRef(Props(new MyActorWithStash()).withDispatcher("deque")) 
2

使用默认的阿卡调度允许我使用StashTestActorRef

val myActor = TestActorRef[MyActor](Props(classOf[MyActor]).withDispatcher("akka.actor.default-dispatcher")) 

注意,这意味着你的测试将不更长时间使用默认CallingThreadDispatcher,将失去突出显示的好处in the akka docs