2013-08-20 15 views
10

Sto incontrando un problema con un attore che estende Stash e che funziona perfettamente quando lo si istanzia con actorOf in un semplice ActorSystem. Ora vorrei davvero scrivere alcuni test per i miei attori che li nascondono prima di usarli nel mio programma. Ma non riesco a capire un modo per utilizzare un TestActorRef con questo attore nella mia suite di test.Test degli attori Akka che mixano Stash con TestActorRef

Il codice che funziona simile a questo:

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" 

che stampa

Unstashed message: stash me 

Unstashed message: blah 

Ma se provo a scrivere un test WordSpec per questo attore, mi lascia con qualche eccezione brutte che posso capisco cosa vorrebbero che io cambiasse nel mio codice.

classe Il test si presenta così

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

Quando si esegue il test, vengo a seguito eccezioni generate durante l'istanza della 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 

Non ho alcun problema con l'utilizzo di TestActorRefs con attori che non estendono Stash. Quindi non so se si tratta di un errore di configurazione o qualcos'altro che mi manca.

risposta

2

sono stato in grado di testare gli attori con Stash in questo modo:

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

Utilizzando il dispatcher di default Akka mi ha permesso di usare Stash e TestActorRef:

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

Si noti che questo significa che i test non saranno utilizzare più a lungo il valore predefinito CallingThreadDispatcher e perderà i vantaggi evidenziati in the akka docs

Problemi correlati