Thursday, September 1, 2011

Testing oneway actors with the stackable trait pattern

Just a quick post on something quite simple our team came up with recently for testing a particular type of Actor.
It comes in handy when you want to test an Actor that receives one-way messages and does not send out any messages, or reply to messages. Maybe after processing you want to assert some state somewhere.

Actors that respond to request/response are very easy to test. You don't have to use any Barriers or Latches or even the (very handy) TestKit, you just ask the Actor to send a reply using !!, and assert on the reply, fail on timeout.

Would it not be nice to test one-way Actors in the same way? What we would like is for the Actor to just send the exact same message back that was sent to it after it is done processing the message. Of course only in a test scenario. That way you would be able to test one-way messages in the same way as request/response messages.

The idea was to dynamically add some code to wrap around the Actor that you would like to test, in some way delegate to the Actor, and always do a reply to the sender with the original message, after the Actor is done with the processing of that message. That way the test becomes very easy, you just send a 'asking' !! to the Actor, the Actor does it's normal thing as if it received a 'telling' ! after which the extra bit of code kicks in and sends the original message back to the unit test, so you know its done its job.

Akka has a nice way of handling  the difference between one-way and request/response. You can use the reply_? message from within an Actor, which replies back to the sender if the sender asked for a response, or does nothing in the event the sender 'told' the Actor something in one-way style.

The easiest way we found to dynamically add a sort of template method was to use a stackable trait (which is described on the artima site here). The below ReplyAfterProcessing trait overrides the receive of the Actor, first applies the Actor's receive (which is a PartialFunction) and chains it with an anonymous partial function that always replies the message.

That way you can test a one-way Actor like this. The "with ReplyAfterProcessing" mixes in the trait and replaces the standard receive processing "dynamically".

Happy hAkking!