pekko/akka-testkit/src/main/scala/akka/testkit/TestActorRef.scala

71 lines
2.5 KiB
Scala
Raw Normal View History

package akka.testkit
import akka.actor._
import akka.util.ReflectiveAccess
import akka.event.EventHandler
/**
* This special ActorRef is exclusively for use during unit testing in a single-threaded environment. Therefore, it
* overrides the dispatcher to CallingThreadDispatcher and sets the receiveTimeout to None. Otherwise,
* it acts just like a normal ActorRef. You may retrieve a reference to the underlying actor to test internal logic.
*
*
* @author Roland Kuhn
* @since 1.1
*/
class TestActorRef[T <: Actor](factory: () => T) extends LocalActorRef(factory, None) {
dispatcher = CallingThreadDispatcher.global
receiveTimeout = None
/**
* Retrieve reference to the underlying actor, where the static type matches the factory used inside the
* constructor. Beware that this reference is discarded by the ActorRef upon restarting the actor (should this
* reference be linked to a supervisor). The old Actor may of course still be used in post-mortem assertions.
*/
def underlyingActor : T = actor.asInstanceOf[T]
/**
* Override to return the more specific static type.
*/
override def start() = {
super.start()
this
}
override def toString = "TestActor[" + id + ":" + uuid + "]"
override def equals(other : Any) =
other.isInstanceOf[TestActorRef[_]] &&
other.asInstanceOf[TestActorRef[_]].uuid == uuid
/**
* Override to check whether the new supervisor is running on the CallingThreadDispatcher,
* as it should be. This can of course be tricked by linking before setting the dispatcher before starting the
* supervisor, but then you just asked for trouble.
*/
override def supervisor_=(a : Option[ActorRef]) {
for (ref <- a) {
if (!ref.dispatcher.isInstanceOf[CallingThreadDispatcher])
EventHandler.warning(this, "supervisor "+ref+" does not use CallingThreadDispatcher")
}
super.supervisor_=(a)
}
}
object TestActorRef {
def apply[T <: Actor](factory: => T) = new TestActorRef(() => factory)
def apply[T <: Actor : Manifest] : TestActorRef[T] = new TestActorRef[T] ({ () =>
import ReflectiveAccess.{ createInstance, noParams, noArgs }
createInstance[T](manifest[T].erasure, noParams, noArgs).getOrElse(
throw new ActorInitializationException(
"Could not instantiate Actor" +
"\nMake sure Actor is NOT defined inside a class/trait," +
"\nif so put it outside the class/trait, f.e. in a companion object," +
"\nOR try to change: 'actorOf[MyActor]' to 'actorOf(new MyActor)'."))
})
}