Search code examples
c#akka.nettestkit

Akka Net Integration Test


I have a fairly simply scenario where I want to do a straight forward integration test. High level overview, is:

  • I have an actor which responds to a message called PlaceOrder
  • I want to verify this actor publishes another message upon receiving PlaceOrder, in this case OrderPlaced

The trouble is, for an integration test I can assert that the message has been published via ExpectMsg<OrderPlaced>. But, I was also expecting it to invoke any actors handling that message too?

Perhaps my understanding of the TestKit is incorrect here but when inheriting from it you get:

  • ActorOfAsTestActorRef<T>
  • ActorOf<T>
  • Sys.ActorOf(...)

My impression was, ActorOf<T> and Sys.ActorOf(...) would behave like a real actor system whereas the ActorOfAsTestActorRef<T> would be ideal for strictly unit tests and swallow any messages an actor may in turn send.

For example, these are my 2 actors in question:

public class PlaceOrderActor : ReceiveActor
{
    public PlaceOrderActor()
    {
        this.Receive<PlaceOrderMessage>(
            message =>
            {
                this.Handle(message);
            });
    }

    private void Handle(PlaceOrderMessage message)
    {
        Context.ActorOf(Props.Create<Foo>()).Tell(new OrderPlaced(message.CustomerId, message.OrderItems));
    }
}

public class Foo : ReceiveActor
{
    public Foo()
    {
        this.Receive<OrderPlaced>(
            m =>
            {
            });
    }
}

My test looks like this. The odd thing I have to orchestrate this integration test myself, i.e. I check that the OrderPlaced has been published and then explicitly send a message to Foo:

[TestFixture]
public class IntegrationTest : TestKit
{
    [Test]
    public void When_Placing_An_Order()
    {
        var message = new PlaceOrderMessage(
            "123",
            new List<OrderItem>
            {
                new OrderItem("Product ABC", 2)
            });

        this.ActorOfAsTestActorRef<PlaceOrderActor>().Tell(message);

        var orderPlaced = this.ExpectMsg<OrderPlaced>();

        //if (orderPlaced != null)
        //{
            //this.ActorOfAsTestActorRef<Foo>().Tell(orderPlaced);
        //}
    }
}

What I am expecting is, by sending the message PlaceOrder this should invoke Foo as it handles OrderPlaced. I shouldn't need to have the bits commented out in the test?

Can this be done or am I going about this completely wrong?

Thanks in advance, DS.


Solution

  • Your PlaceOrderActor doesn't have a reference to the FooActor, it responds to the Sender, which is the Testkit actor.

    If you want the FooActor to receive the OrderPlaced message, you're going to need to tell it the message in your PlaceOrderActor.Handle() method. You'll likely need to create the FooActor as a child of the PlaceOrderActor, or otherwise resolve the reference to it if it's elsewhere in your system (in this case there is no FooActor running in the system at all). How does this work in your actual (ie. non-test) system, or does this only exist as test code so far?

    Be aware that if you send the OrderPlaced message to the FooActor, and don't tell any message back to the Sender of PlaceOrderActor, there will be no observable effect from within your test method, so your FooActor will need to respond either directly to the original sender, or back to the PlaceOrderActor which in turn can respond to the original sender.