I am using akka actors in my java project and I am facing difficulties while writing unit tests for the same. I have written sample code as mentioned below to illustrate my use case.
MainActor
is kind of controller actor which receives akka messages but it will not respond anything to the sender. It will send same or different message to some other actor whose ActorRef
is created during its initialization.
package sample;
import akka.actor.AbstractActor;
import akka.actor.ActorRef;
import akka.actor.ActorSystem;
import akka.actor.Props;
public class MainActor extends AbstractActor {
private final ActorSystem actorSystem;
private final ActorRef subActor1;
private final ActorRef subActor2;
public MainActor(ActorSystem actorSystem) {
this.actorSystem = actorSystem;
subActor1 = this.actorSystem.actorOf(Props.create(SubActor1.class));
subActor2 = this.actorSystem.actorOf(Props.create(SubActor2.class));
}
@Override
public Receive createReceive() {
return receiveBuilder()
.match(InitSubActor1.class, msg -> {
subActor1.tell(msg, self());
})
.match(InitSubActor2.class, msg -> {
subActor2.tell(msg, self());
})
.build();
}
public static class InitSubActor1 {
}
public static class InitSubActor2 {
}
}
SubActor1:
package sample;
import akka.actor.AbstractActor;
public class SubActor1 extends AbstractActor {
@Override
public Receive createReceive() {
return receiveBuilder()
.match(MainActor.InitSubActor1.class, msg -> {
System.out.println("Received InitSubActor1");
})
.build();
}
}
SubAcotor2:
package sample;
import akka.actor.AbstractActor;
public class SubActor2 extends AbstractActor {
@Override
public Receive createReceive() {
return receiveBuilder()
.match(MainActor.InitSubActor2.class, msg -> {
System.out.println("Received InitSubActor2");
})
.build();
}
}
As shown above, when MainActor
receives message of type MainActor.InitSubActor1
, it will send it to SubActor1
and similar thing happens when it receives message of type MainActor.InitSubActor2
.
Now I want to write unit tests for MainActor
such that when I send MainActor.InitSubActor1
message from my unit test, I want to assert that MainActor
sends it to SubActor1
. I tried to explore TestProbe
and found that we can verify actor messages if an actor responds to the sender but I could not find a way to verify the scenario where actor sends message to another actor instead of sender actor.
Below is the unit test which I tried.
package sample;
import akka.actor.ActorRef;
import akka.actor.ActorSystem;
import akka.actor.Props;
import akka.testkit.TestProbe;
import akka.testkit.javadsl.TestKit;
import org.junit.Test;
import static org.mockito.Mockito.spy;
public class MainActorTest {
private ActorSystem actorSystem = spy(ActorSystem.create());
@Test
public void testActor() {
new TestKit(actorSystem) {
{
final TestProbe probe = TestProbe.apply(actorSystem);
final Props props = Props.create(MainActor.class, actorSystem);
final ActorRef mainActor = actorSystem.actorOf(props);
mainActor.tell(new MainActor.InitSubActor1(), getRef());
probe.expectMsgClass(MainActor.InitSubActor1.class);
}
};
}
}
This fails since MainActor
is not actually replying back to sender. I guess this is not suitable for the use case that I am trying to test. Please let me know if there is any way to write unit tests to verify akka messages sent to different actors.
Note: I can not pass ActorRef
of SubActor1
and SubActor2
to the constructor of MainActor