1

I have Akka.Net code similar to the following and I am trying to write tests for it:

public class DoesSomethingActor : UntypedActor
{
    protected override void OnReceive(object message)
    {

    }
}

public class ForwardsMessagesActor : UntypedActor
{
    protected override void OnReceive(object message)
    {
        var actor = Context.ActorOf(Context.DI().Props<DoesSomethingActor>(), "DoesSomethingWorker");

        for (int i = 0; i < 5; i++)
        {
            actor.Tell(message + " " + i);
        }
    }
}

I have got this test working but I am clearly missing something since I am not using much of TestKit at all. Is there still no official documentation for how to test this using TestKit ?

//creating actor mocks with Moq seems to confuse Akka - it just doesn't work 
//but creating mock classes manually like this, 
//then configuring them in the DI container works
public class DoesSomethingActorSpy : DoesSomethingActor
{
    public static List<object> ReceivedMessages = new List<object>();

    protected override void OnReceive(object message)
    {
        ReceivedMessages.Add(message);
    }
}

    [TestMethod]
    public void ForwardsMessagesActor_Creates5Messages()
    {
        //set up DI container to use DoesSomethingActorSpy as a child actor
        ContainerBuilder builder = new ContainerBuilder();
        builder.RegisterType<ForwardsMessagesActor>();
        builder.RegisterType<DoesSomethingActorSpy>().As<DoesSomethingActor>();
        IContainer container = builder.Build();

        var propsResolver = new AutoFacDependencyResolver(container, Sys);

        var actor = ActorOfAsTestActorRef<ForwardsMessagesActor>(propsResolver.Create<ForwardsMessagesActor>());

        actor.Tell("Test");

        //this looks wrong, I probably should be using something from TestKit
        Thread.Sleep(10);

        CollectionAssert.AreEquivalent(
            new[] { "Test 0", "Test 1", "Test 2", "Test 3", "Test 4" },
            DoesSomethingActorSpy.ReceivedMessages);
    }

How should I create mock actors? Is there any method on TestKit I can call to wait until all messages have been processed?

4

1 回答 1

5

引自How to Test Akka.NET Actors: Unit Testing w/Akka.TestKit

测试父/子关系更复杂。这是 Akka.NET 对提供简单抽象的承诺使测试变得更加困难的一种情况。

测试这种关系的最简单方法是使用消息传递。例如,您可以创建一个父actor,一旦它启动,它的子actor就会向另一个actor发送消息。或者您可以让父母将消息转发给孩子,然后孩子可以回复原始发件人,例如:

public class ChildActor : ReceiveActor
{
    public ChildActor()
    {
        ReceiveAny(o => Sender.Tell("hello!"));
    }
}

public class ParentActor : ReceiveActor
{
    public ParentActor()
    {
        var child = Context.ActorOf(Props.Create(() => new ChildActor()));
        ReceiveAny(o => child.Forward(o));
    }
}

[TestFixture]
public class ParentGreeterSpecs : TestKit
{
    [Test]
    public void Parent_should_create_child()
    {
        // verify child has been created by sending parent a message
        // that is forwarded to child, and which child replies to sender with
        var parentProps = Props.Create(() => new ParentActor());
        var parent = ActorOfAsTestActorRef<ParentActor>(parentProps, TestActor);
        parent.Tell("this should be forwarded to the child");
        ExpectMsg("hello!");
    }
}

测试亲子关系的注意事项

避免将代码过度耦合到层次结构!

过度测试父/子关系可以将您的测试与您的层次结构实现结合起来。这会通过强制许多测试重写来增加以后重构代码的成本。您需要在验证您的意图和测试您的实现之间取得平衡。

于 2015-11-17T17:48:52.277 回答