There are many examples of using akka-testkit when the Actor being tested is responding to an ask:
//below code was copied from example link
val actorRef = TestActorRef(new MyActor)
// hypothetical message stimulating a '42' answer
val future = actorRef ? Say42
val Success(result: Int) = future.value.get
result must be(42)
But I have an Actor that does not respond to a sender; it instead sends a message to a separate actor. A simplified example being:
class PassThroughActor(sink : ActorRef) {
def receive : Receive = {
case _ => sink ! 42
}
}
TestKit has a suite of expectMsg methods but I cannot find any examples of creating a test sink Actor that could expect a message within a unit test.
Is it possible to test my PassThroughActor?
Thank you in advance for your consideration and response.
As mentioned in the comments you can use a TestProbe to solve this:
val sink = TestProbe()
val actorRef = TestActorRef(Props(new PassThroughActor(sink.ref)))
actorRef ! "message"
sink.expectMsg(42)
Related
#Singleton
class EventPublisher #Inject() (#Named("rabbit-mq-event-update-actor") rabbitControlActor: ActorRef)
(implicit ctx: ExecutionContext) {
def publish(event: Event): Unit = {
logger.info("Publishing Event: {}", toJsObject(event), routingKey)
rabbitControlActor ! Message.topic(shipmentStatusUpdate, routingKey = "XXX")
}
}
I want to write a unit test to verify if this publish function is called
rabbitControlActor ! Message.topic(shipmentStatusUpdate, routingKey = "XXX")
is called only once.
I am using spingo to publish messages to Rabbit MQ.
I am using Playframework 2.6.x and scala 2.12.
You can create an TestProbe actor with:
val myActorProbe = TestProbe()
and get its ref with myActorProbe.ref
After, you can verify that it receives only one message with:
myActorProbe.expectMsg("myMsg")
myActorProbe.expectNoMsg()
You probably should take a look at this page: https://doc.akka.io/docs/akka/2.5/testing.html
It depends you want to check only the message is received by that actor or you want to test the functionality of that actor.
If you want to check message got delivered to the actor you can go with TestProbe. I.e.
val probe = TestProbe()
probe.ref ! Message
Then do :
probe.expectMsg[Message]
You can make use of TestActorRef in case where you have supervisor actor, which is performing some db operations so you can over ride its receive method and stop the flow to go till DB.
I.e.
val testActor =new TestActorRef(Actor.props{
override receive :Receive ={
case m:Message => //some db operation in real flow
//in that case you can return what your actor return from the db call may be some case class.
case _ => // do something }})
Assume your method return Future of Boolean.
val testResult=(testActor ? Message).mapTo[boolean]
//Then assert your result
I want to test that an actor A send a message to an actor B after have received a message.
I'm using Play! 2.5 and I use the factories since I need to inject some of my classes and things like wSClient inside the actors.
The Actor A looks like:
object ActorA {
trait Factory {
def apply(ec: ExecutionContext, actorBRef: ActorRef): Actor
}
}
class ActorA #Inject()(implicit val ec: ExecutionContext,
#Named("actor-b") actorBRef: ActorRef)
extends Actor with ActorLogging with InjectedActorSupport {
override def receive: Receive = {
case i: Long =>
log info s"received $i"
actorBRef ! (i+1)
}
And the actor B is even more simple:
object ActorB {
trait Factory {
def apply(): Actor
}
}
class ActorB extends Actor with ActorLogging {
override def receive: Receive = {
case _ =>
log error "B received an unhandled message"
}
}
But my test doesn't pass, it is said that the expected message doesn't arrive, I get a Timeout in the test (but it is well logged by the actor B) so the problem comes from the test (and probably the Probe).
Here is the test:
val actorBProbe = TestProbe()
lazy val appBuilder = new GuiceApplicationBuilder().in(Mode.Test)
lazy val injector = appBuilder.injector()
lazy val factory = injector.instanceOf[ActorA.Factory]
lazy val ec = scala.concurrent.ExecutionContext.Implicits.global
lazy val factoryProps = Props(factory(ec, actorBProbe.ref))
val ActorARef = TestActorRef[ActorA](factoryProps)
"Actor B" must {
"received a message from actor A" in {
ActorARef ! 5L
actorBProbe.expectMsg(6L)
}
}
I also created a minimum Play! application with the code above available here.
In your test, actorBProbe is not the ActorB ref passed to ActorA constructor (of ref ActorARef). What really happens is that Guice creates a different ActorB (named actor-b), and passes its ref to ActorA (of ref ActorARef) constructor.
The test ends up with ActorB actor-b receiving 6L (as evident in log). While actorBProbe receives nothing.
The confusion really comes from mixing Guice lifecyle with Actors. In my experience, it creates more pains than I can bear.
To prove, simply print hash code of ActorRef's, you'll see they are different. Illustrated as followings:
val actorBProbe = TestProbe()
println("actorBProbe with ref hash: " + actorBProbe.ref.hashCode())
And,
class ActorA ... {
override def preStart =
log error "preStart actorBRef: " + actorBRef.hashCode()
// ...
}
In fact, even ec inside ActorA is not the same ec in the test code.
The following is a way to "force" the test to pass and at the same time prove that actorBProbe wasn't really being used by ActorB.
In stead of relying on Guice to "wire in" ActorB, we tell Guice to leave it alone by replacing #Named("actor-b") with #Assisted, like this,
import ...
import com.google.inject.assistedinject.Assisted
class ActorA #Inject()(...
/*#Named("actor-b")*/ #Assisted actorBRef: ActorRef)
...
Re-run the test, it'll pass. But this is probably not what you wanted to begin with.
In my Spray route, I delegate to an actor to process the request. The RequestContext is sent in the message to that actor.
path("mypath") {
parameters("thing".as[String]) { thing => ctx =>
myActor ! ProcessThingAndResondToContext(thing, ctx)
}
}
In my test, I substitute a TestProbe for the actor, because the actor's processing is expensive.
class MySpec extends Specification with Specs2RouteTest with ScalaCheck with MyService {
val testProbe = TestProbe()
override val myActor = testProbe.ref
def is = s2"""
it should $doTheRightThing
"""
def doTheRightThing = {
Get(s"/mypath?thing=fruit") ~> route ~> check {
testProbe.expectMsgClass(classOf[ProcessThingAndResondToContext])
status mustEqual StatusCodes.Success
}
}
This spec fails because there's no status. The TestProbe does nothing and so the ctx was never responded to.
Request was neither completed nor rejected within 1 second
The line status mustEqual StatusCodes.Success is not crucial to my test, but I can't remove it because then the spec doesn't compile - the method no longer typechecks as a MatchResult.
How can I test the route delegated to the actor?
I didn't solve the question, but resolved my problem by using a TestActorRef instead of a TestProbe. Then I could specify a simplified behaviour and still respond to ctx.
I have the following Actor Model declaration in akka:
val wireA = system.actorOf(Props(new Wire(false)), "Input")
val wireB = system.actorOf(Props(new Wire(false)), "Output")
inverter ! generateOutput(wireA, wireB)
From the generateOutput(input:ActorRef, output:ActorRef),
I need to access the boolean parameter which constructs each particularActorRef (i.e the paramater false which is found in each respective Wire Constructor.
How does it can be reached?
You can send a message to each actor, asking for its current status:
case object Status
case object StatusResult(value: Boolean)
class MyActor(wire: ActorRef) extends Actor {
wire ! Status
def receive = {
case StatusResult(value) => ...
}
wireA and wireB are ActorRefs, they do not expose their state and the only way to communicate with them is via messages.
It's not the way you should play with Actors. You get the ActorRef and you you play with it only with the messages. You can ask the actor of the value of the boolean by passing a message to it:
wireA ! "getVal"
and waiting for the response in the sender actor. Please check the basic tutorial on Actors:
http://alvinalexander.com/scala/scala-akka-actors-ping-pong-simple-example
So I'm getting started using Akka actors inside of my Play 2.0 app. I noticed quickly that repeated calls to sending messages to the same actor, specified via:
val myActor = Akka.system.actorOf(Props[MyActor], name = "myactor")
Resulted in InvalidActorNameException.
I then started reading up on the creation of Actors in this doc
The doc seemed to recommend creating a "master" Actor class with all of the individual actors specified in there. The receive of this actor class would, in turn, match on the message and delegate the message to the appropriate Actor.
So I tried this and now have something like:
class MasterActor extends Actor{
import context._
val emailActor = actorOf(Props[EmailActor], name = "emailActor")
protected def receive = {
case reminder : BirthdayReminder => emailActor ! reminder
}
}
Problem is that I'm in the same situation I was before. I don't know how to avoid the InvalidActorNameException when I try something like:
val myActor = Akka.system.actorOf(Props[MasterActor], name = "MasterActor")
myActor ! BirthdayReminder(someBirthday)
So what's the right way to organize my Actors?
If you want only one MasterActor, why are you creating multiple ones? You should just look up the one you have already created:
val actorRef = context.actorFor("MasterActor")
actorRef ! BirthdayReminder(someBirthday)