2

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.

Dr Schizo
  • 4,045
  • 7
  • 38
  • 77

1 Answers1

1

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.

Patrick Allwood
  • 1,822
  • 17
  • 21
  • I was on the akka net gitter room about this and it seems as though I don't have the foo actor running hence the message is being swallowed. I believe in my setup I simply need to add ActorOf Foo and it should work. You are right I have only tried this from a test perspective. I have something extremely similar to this running in a console app. – Dr Schizo Mar 31 '16 at 12:47
  • You're post got me thinking so I created a `Client` which simply serves as a sender of messages to the `Server`. This seems to work fine, i.e. I send `PlaceOrderMessage` which is handled by an `PlaceOrderActor`. I then use `Context.ActorOf(Props.Create()).Tell(new OrderPlaced(message.CustomerId, message.OrderItems));`. However, when using TestKit this message is swallowed? – Dr Schizo Apr 01 '16 at 09:51
  • Apologies you are correct. Created a child actor worked a treat. The problem I was just experiencing happened to be I was using `ActorOfAsTestActorRef` which runs on a separate thread to `Sys.ActorOf()` (to my knowledge) and hence the assert of `ExpectMsg<>` was failing. Updating post to show the working solution. – Dr Schizo Apr 01 '16 at 09:56