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
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.
This way, this functionality can be unit tested very easy. For the real actor I try to stick to implement the receive method only.
Then when testing the actor, you can override the getHelloMessage implementation to do whatever you want.
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.
To mock an actor is easier through the TestActorRef. You can use this code :
Note: ClassToBeMocked--Its a class you want to mock. MockedResultActor -- Its a class you want to return after mocking. This can be run using JunitTest after implementing basic configuration of mocking in your class. Code given here is specific to akka actor in java only.
So I'm probably not understanding the question but you probably don't want to mock an actor as the purpose of mocking is to replace something like a dao with a test copy that has expectations of invocation - actor doesn't really fit the bill as it's something you extend rather than a dependency - mocking really only applies to real dependencies.
TestActorRef specifically gives you access to the underlying actor - in most normal circumstances you can only send messages to an actor and not invoke anything directly on it. TestActoRef removes this limitation by allowing you to access your real true extension of Actor instead of just the ActorRef that you can only ! or ? against (send or ask).
I'm a scala dev so the insight is hopefully agnostic. I don't know the java api specifically but it shouldn't matter.
My recommendation is to get the real Actor object via actor ref and just test the method or figure out some way to get test coverage through real messages.
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.htmlHere'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.