I have a fairly simply scenario where I want to do a straight forward integration test. High level overview, is:
actor
which responds to a message called PlaceOrder
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.
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.