2013-08-20 13 views
10

Występuje problem z aktorem, który rozszerza Stash i który działa idealnie dobrze, gdy tworzy się go za pomocą actorOf w prostym ActorSystem. Teraz chciałbym napisać kilka testów dla moich aktorów, zanim użyję ich w moim programie. Ale nie mogę znaleźć sposobu na użycie TestActorRef z tym aktorem w moim pakiecie testowym.Testowanie aktorów Akka, które mieszają Stash z TestActorRef

Kod, który działa i wygląda tak:

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" 

która drukuje

Unstashed message: stash me 

Unstashed message: blah 

Ale gdy próbuję napisać test WordSpec dla tego aktora, pozostawia mnie rzęsiste wyjątkami mogę nie wiem, co chcieliby zmienić w moim kodzie.

klasa Test wygląda następująco

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) 
} 

Po uruchomieniu testu, otrzymuję następujące wyjątki, które są wyrzucane podczas konkretyzacji w 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 

Nie mam żadnych problemów z używaniem TestActorRefs z aktorami, którzy nie rozszerzają pamięci podręcznej. Nie wiem, czy jest to błąd konfiguracji, czy coś innego, czego mi brakuje.

Odpowiedz

2

udało mi się przetestować aktorów z Stash tak:

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

Korzystanie dyspozytora domyślny Akka pozwolił mi korzystać Stash i TestActorRef:

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

pamiętać, że oznacza to twoje testy nie będzie dłużej używać domyślnego CallingThreadDispatcher i straci korzyści podświetlone in the akka docs

Powiązane problemy