I\'m interested to know about how to test Akka Actor functionality, by mocking some methods (substitute real object\'s/actor\'s method implementation by moc
I have no experience in using Akka with Java, but I guess the solution for this I use in Scala can also apply to Java. There is no need at all to mock anything. In Java mocking is sometimes useful for testing, but my personal experience/opinion is that whenever you need PowerMock you're doing something wrong.
Here's how I try to test using Akka:
In Scala I use a trait (aka interface) in which the actor methods are defined.
trait ToBeTested {
def getHelloMessage(msg: String, replyTarget: ActorRef): String =
replyTarget ! s"Hello $msg"
}
This way, this functionality can be unit tested very easy. For the real actor I try to stick to implement the receive method only.
class ToBeTestedActor extends Actor with ToBeTested {
def receive: Receive = {
case msg: String => getHelloMessage(msg, sender())
}
}
Then when testing the actor, you can override the getHelloMessage implementation to do whatever you want.
class ToBeTestedActorTest extends TestKit(ActorSystem("toBeTested") with .... {
trait MyToBeTested extends ToBeTested {
// do something predictable for testing or defer to a TestProbe which you can
// either define globally in the test class or provide one in a constructor.
override def getHelloMessage(msg: String, replyTarget: ActorRef): String = ???
}
val toBeTestedActor = TestActorRef(Probe(new ToBeTestedActor with MyToBeTested))
// ... (test cases)
}
In Java you can do pretty much the same thing. Since Java 8 you can provide default method implementations in interfaces, which you can override in a sub-interface for testing. Another way would be to subclass the actor in your test to override some methods to provide predictable behaviour.
// An easy unit testable interface
public interface ToBeTested {
public ActorRef self();
default public void getHelloMessage(String msg, ActorRef replyTarget) {
replyTarget.tell(String.format("Hello %s", msg), self());
}
}
public class ToBeTestedActor extends UntypedActor implements ToBeTested {
// self() already implemented by Actor class
@Override
public void onReceive(Object message) throws Exception {
if (message instanceof String) {
getHelloMessage((String)message, getSender());
}
}
}
public class ToBeTestedActorTest {
@Test
public void test() throws Exception {
ActorSystem system = ActorSystem.create();
TestActorRef testActorRef = TestActorRef.create(system, Props.create(TestActor.class));
Future