1
votes

I am trying to test an Akka Actor in java. This is what the test is trying to do, code is below

  • This actor under test subscribes to the evenstream in his constructor.
  • The actor is created in the test using the normal actorOf on the actorsystem.
  • This returns an ActorRef, the real actor however is being created behind the scenes asynchronously.
  • I publish a message on the eventstream in my test.
  • However, since the actor is constructed asynchronously, the message is published on the eventstream before the actor subscribes itself to the eventstream.
  • Result: the actor under test never sees the message and nerver forwards it to the actor he should forward the message to. The test fails, since the actor to forward to is a testprobe in this test on which we expect the message to arrive.

I could sleep or wait for a moment before publishing the message to the eventstream, but isn't there a "cleaner" way to check that the actor is fully up and running? Can I listen for some event on the eventstream that tells me the actor has finished creating himself?

@Test
public void testListenOnEventStreamAndForward() throws InterruptedException
{
    // given
    final TestProbe actorToForwardMessageTo = new TestProbe(this.actorSystem);
    final Function<ActorRefFactory, ActorRef> actorToForwardMessageTosFactoryFunction = (actorRefFactory) -> actorToForwardMessageTo.ref();
    this.actorSystem.actorOf(Props.create(ActorUnderTest.class, () -> new ActorUnderTest(actorToForwardMessageTosFactoryFunction)));

    //The test is green, depending on the whether we sleep here or not
    //Thread.sleep(1000);

    // when
    this.eventStream.publish("someStringMessageTheActorUnderTestShouldPickUp");

    // then
    actorToForwardMessageTo.expectMsg("someStringMessageTheActorUnderTestShouldPickUp");
}


private static class ActorUnderTest extends AbstractActor
{

    public ActorUnderTest(final Function<ActorRefFactory, ActorRef> actorToForwardMessageToFactoryFunction) throws Exception
    {
        context().system().eventStream().subscribe(self(), String.class);
        final ActorRef actorToForwardMessageTo = actorToForwardMessageToFactoryFunction.apply(getContext());

        receive(ReceiveBuilder
                .match(
                        String.class,
                        stringMessage -> actorToForwardMessageTo.tell(stringMessage, self()))
                .matchAny(
                        message -> unhandled(message))
                .build());
    }

}
1
What if you use the resolveOne function in your test?rethab
resolveOne works on actorPath if I am not mistaken. I only have the actorRef available.Jo Vanthournout

1 Answers

0
votes

You could use an awaitAssert to retry publishing/expecting message up until a timeout before failing. See the awaitAssert section in the docs here: http://doc.akka.io/docs/akka/2.4/java/testing.html