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 mocked one) in Actor.
I use akka.testkit.TestActorRef
;
Also: I tried to use SpyingProducer
but it is not clear how to use it. (like I if I created actor inside its implementation it would be the same I have now).
The google search result about that is not very verbose.
I use powemockito
and java
. But It does not matter. I would be interested to know how to do it in principle
with any language with any framework
(so if you do not know how power/mockito works just provide your code.. (please) or complete idea about how you would do it with your tools you know.)
So, let's say we have an Actor to test:
package example.formock;
import akka.actor.UntypedActor;
public class ToBeTestedActor extends UntypedActor {
@Override
public void onReceive(Object message) throws Exception {
if (message instanceof String) {
getSender().tell( getHelloMessage((String) message), getSelf());
}
}
String getHelloMessage(String initMessage) { // this was created for test purposes (for testing mocking/spy capabilities). Look at the test
return "Hello, " + initMessage;
}
}
And in our test we want to substitute getHelloMessage()
returning something else.
This is my try:
package example.formock;
import akka.testkit.TestActorRef;
...
@RunWith(PowerMockRunner.class)
@PrepareForTest(ToBeTestedActor.class)
public class ToBeTestedActorTest {
static final Timeout timeout = new Timeout(Duration.create(5, "seconds"));
@Test
public void getHelloMessage() {
final ActorSystem system = ActorSystem.create("system");
// given
final TestActorRef<ToBeTestedActor> actorRef = TestActorRef.create(
system,
Props.create(ToBeTestedActor.class),
"toBeTestedActor");
// First try:
ToBeTestedActor actorSpy = PowerMockito.spy(actorRef.underlyingActor());
// change functionality
PowerMockito.when(actorSpy.getHelloMessage (anyString())).thenReturn("nothing"); // <- expecting result
try {
// when
Future<Object> future = Patterns.ask(actorRef, "Bob", timeout);
// then
assertTrue(future.isCompleted());
// when
String resultMessage = (String) Await.result(future, Duration.Zero());
// then
assertEquals("nothing", resultMessage); // FAIL HERE
} catch (Exception e) {
fail("ops");
}
}
}
Result:
org.junit.ComparisonFailure:
Expected :nothing
Actual :Hello, Bob
Akka has a class AutoPilot
that is basically a general mock for actors, with the ability to respond to messages and assert that messages were sent.
http://doc.akka.io/docs/akka/snapshot/java/testing.html
Here's the java example for that page. You create a probe, set an auto-pilot that can respond to messages, and get an ActorRef
from it that you can substitute in for your real actor.
new JavaTestKit(system) {{
final JavaTestKit probe = new JavaTestKit(system);
// install auto-pilot
probe.setAutoPilot(new TestActor.AutoPilot() {
public AutoPilot run(ActorRef sender, Object msg) {
sender.tell(msg, ActorRef.noSender());
return noAutoPilot();
}
});
// first one is replied to directly ...
probe.getRef().tell("hello", getRef());
expectMsgEquals("hello");
// ... but then the auto-pilot switched itself off
probe.getRef().tell("world", getRef());
expectNoMsg();
}};