I'd like to be able to assert against a value that is "stored" into the Receive function of my actor. Is there a way to do that with any of the Akka Test libraries?
In the example below, I'd like to obtain currentCount
.
import akka.actor.Actor
class CounterActor extends Actor {
import CounterActor._
override def receive: Receive = count(0)
def count(currentCount: Int): Receive = {
case Increment => context.become(count(currentCount + 1))
case Decrement => context.become(count(currentCount - 1))
}
}
object CounterActor {
case object Increment
case object Decrement
}
Then I'd like to assert against it with a Test class:
val counterActorRef = TestActorRef(new CounterActor())
"A counter actor" should {
"have a count of 3" in {
counterActorRef ! CounterActor.Increment
counterActorRef ! CounterActor.Increment
counterActorRef ! CounterActor.Increment
val counterValue = // obtain currentCount from counterActorRef
assert(counterValue == 3)
}
}
I've tried using using TestActorRef, but haven't been successful. I know there's a way to satisfy this by adding a message case to obtain it, or adding some Debug/Info level log messages and using EventFilter
. Is there simple way to obtain it with a test library that I'm unaware of?
I've searched through akka.testkit
libraries for a while now, but I can't find my solution.
Any help is appreciated, thank you.
The actor model is marked by two qualities:
the encapsulation of an actor's state is radical and (on the JVM, effectively (because it might be possible to break the encapsulation via reflection)) complete.
the observation that an actor's state matters only to the extent that its behavior (how it responds to messages, and in the case of Akka (where it's not "actors all the way down") what side effects it performs) changes as a consequence of that state.
In order to validate that a state transition happens, you can only test that it behaves as expected. Exposing a query message is one way to do it; things like tapping the stream of log entries or (if event-sourcing, the stream of persistence events) are others.
That said, exposing a query message for the sole purpose of enabling testability is often not the way to go (it may be useful for operational debugging). The ideal would be to test the "in-band" behavior of the actor in response to the state-change (e.g. "after sending a message for which A is true, the responses to messages where B is true exhibit property C"). If the state-change doesn't manifest itself as a change in behavior in some way, why is the state-change even happening?
Put another way, it's generally good to think of each other actor as a blackbox service. If you were testing SO, you couldn't possibly validate that "after posting a question, this field in the DB is set to this value" (because you as a user don't have access to a DB and you can't supply a mock which you control to SO). What you can validate is that "when I post a question, I get a question ID back and when I request that ID, I get back the content of the question".