测试从测试参与者发送的消息时,akkaNet 测试套件出现问题

akkaNet test kit issue when testing messges sent from tested actor

我正在尝试测试从测试参与者发送的消息,但收到超时异常和死信信息。 因为我正在使用 ninject - 创建了一个模拟方法,它总是使用探测演员参考重播。 我在这里遗漏了什么吗?

        Assert.Fail failed. Failed: Timeout 00:00:03 while waiting for a message of type System.Type 
       at Akka.TestKit.TestKitBase.InternalExpectMsgEnvelope(Nullable`1 timeout, Action`2 assert, String hint, Boolean shouldLog)
       at Akka.TestKit.TestKitBase.InternalExpectMsgEnvelope(Nullable`1 timeout, Action`1 msgAssert, Action`1 senderAssert, String hint)
       at Akka.TestKit.TestKitBase.InternalExpectMsg(Nullable`1 timeout, Action`1 msgAssert, String hint)
       at Akka.TestKit.TestKitBase.ExpectMsg(T message, Nullable`1 timeout, String hint)
       at 

AutoApply.UnitTests.SomethingProcessorActors.SomethingProcessorActorTests.SomethingProcessorActorWhenMergeDataAndGetsNoProfilesLogsThat() in SomethingProcessorActorTests.cs: line 58

    [WARNING][12/02/2016 16:12:43][Thread 0009][akka://test/user/testProbe] DeadLetter from [akka://test/temp/d]

to [akka://test/user/testProbe]: [INFO][12/02/2016 16:12:43][Thread 0011][akka://test/user/testProbe] Message GetOneSomethingAndRemoveFromList from akka://test/temp/d to akka://test/user/testProbe was not delivered. 1 dead letters encountered. Debug Trace: Setting probe reference: akka://test/user/testProbe GetDataActorPath for:SomethingsDataActor GetDataActorPath =>akka://test/user/testProbe GetDataActorPath for:SomethingCollectorActor GetDataActorPath =>akka://test/user/testProbe

    [TestClass]
    public class SomethingProcessorActorTests : TestKit
    {
        /// <summary>The factory helper</summary>
        private IMockingExtension factoryHelper;

        private TestProbe probeActorRef;

        /// <summary>Configurations this instance.</summary>
        [TestInitialize]
        public void Config()
        {

            this.probeActorRef = this.CreateTestProbe("testProbe");
            this.factoryHelper = new MockingFactoryHelper();
            this.factoryHelper.SetProbe(this.probeActorRef.TestActor);
        }

        /// <summary>Somethings the processor actor when merge data and gets no profiles logs that.</summary>
        [TestMethod]
        public void SomethingProcessorActorWhenMergeDataAndGetsNoProfilesLogsThat()
        {
            // arrange
            var actor =
                this.Sys.ActorOf(
                    Props.Create(() => new SomethingProcessorActor(this.factoryHelper as IActorPathAndFactory)),
                    "SomethingActor");

            // act
            actor.Tell(new SomethingProcessorActor.ProcessSomethings());

            // assert
            this.probeActorRef.ExpectMsgFrom<SomethingsDataActor.GetOneSomethingAndRemoveFromList>(actor, new TimeSpan(0, 0, 0, 5));

        }
    }
    =======================
 public partial class SomethingProcessorActor : ReceiveActor
{
    /// <summary>The helper</summary>
    private readonly IActorPathAndFactory helper;

    /// <summary>The log</summary>
    private readonly ILoggingAdapter log = Context.GetLogger();

    /// <summary>The vote execution profile</summary>
    private List<SomethingProcessingObject> voteExecutionProfile = new List<SomethingProcessingObject>();

    /// <summary>
    /// Initializes a new instance of the <see cref="SomethingProcessorActor"/> class.
    /// </summary>
    /// <param name="helper">
    /// The helper.
    /// </param>
    public SomethingProcessorActor(IActorPathAndFactory helper)
    {
        this.helper = helper;
        this.Receive<ProcessSomethings>(
            x =>
                {
                    this.log.Debug("Received: ProcessSomethings");
                    this.BecomeStacked(this.Working);
                    this.RetriveSomethingAndPushForProcessing();
                });
    }



    /// <summary>Supervisors strategy.</summary>
    /// <returns>Supervisors strategy for that actor</returns>
    protected override SupervisorStrategy SupervisorStrategy()
    {
        return new AllForOneStrategy(10, 3000, Decider.From(x => Directive.Stop));
    }



    /// <summary>
    /// The merge data.
    /// </summary>
    private void RetriveSomethingAndPushForProcessing()
    {
     this.log.Debug($"Processing Somethings...");
        var SomethingActor1 = this.helper.GetActorPath(ActorsEnum.SomethingsDataActor);
        var SomethingActor2 =  this.helper.GetActorPath(ActorsEnum.SomethingCollectorActor);
        var something = (SomethingDto)SomethingActor1.Ask(new SomethingsDataActor.GetOneSomethingAndRemoveFromList()).Result;

        while (Something.SomethingId>0)
        {
            this.log.Debug($"Sending data to SomethingCollector with Something id: {Something.SomethingId}");
            SomethingActor2.Tell(new SomethingCollectorActor.ProcessSomethingDto(Something));
            Something = (SomethingDto)SomethingActor1.Ask(new SomethingsDataActor.GetOneSomethingAndRemoveFromList()).Result;
        }

        this.log.Debug("Sending data to SomethingCollector -- ALL SENT");
        this.UnbecomeStacked();
    }

The mock objects just send probe actor as per every request

    public ActorSelection GetActorPath(ActorsEnum actorsEnum)
            {
                Debug.WriteLine("GetDataActorPath for:" + actorsEnum);
                Debug.WriteLine("GetDataActorPath =>" + this.probeRef.Path);

                return this.Sys.ActorSelection(this.probeRef.Path);
            }

            public void SetProbe(IActorRef actorRef)
            {
                Debug.WriteLine("Setting probe reference: " + actorRef.Path);
                this.probeRef = actorRef;
            }

ignition overview

好的,所以有几件事。

首先:您期待的消息类型为:SomethingsDataActor.GetOneSomethingAndRemoveFromList。 但看起来您实际上并没有将此消息传递给由 testprobe 表示的 actorref。但是很难确定,因为你只粘贴了一半的代码。

第二个:

  • 在 actor 内部使用 ask 被认为是一种反模式,可以通过采用更对话式的交流方式轻松避免。
  • 使用actor.ask()。结果更糟,因为如果不小心,可能会导致死锁。 (当数据库 actor 因网络中断而崩溃时会发生什么?可能永远不会发回任何响应,并且默认的 Ask 超时是无限的)

Ask 应该真正用于与 actor 系统外部的 actor 交流。

问题出在继承 TestClass 的模拟 class,

决定 "Actor System Reference"

 return this.Sys.ActorSelection(this.probeRef.Ref.Path);

但应该是:

return this.probeRef.ActorSelection(this.probeRef.Ref.Path);

这种继承正在创建第二个独立的演员系统.....

感谢@Dantar 的帮助!