【问题标题】:akkaNet test kit issue when testing messges sent from tested actor测试从测试参与者发送的消息时出现 akka Net 测试工具包问题
【发布时间】:2016-05-23 21:30:15
【问题描述】:

我试图测试从被测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() 在SomethingProcessorActorTests.cs:第58行

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

到 [akka://test/user/testProbe]: [INFO][12/02/2016 16:12:43][Thread 0011][akka://test/user/testProbe] 消息 GetOneSomethingAndRemoveFromList 从 akka://test/temp/d 到 akka://test/user/testProbe 未交付。 1个死信 遭遇。 调试跟踪: 设置探针参考: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

【问题讨论】:

    标签: akka.net


    【解决方案1】:

    好吧,有几件事。

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

    第二:

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

    Ask 应该只用于与来自 Actor 系统外部的 Actor 进行通信。

    【讨论】:

    • @Dantar - 感谢您的建议。所以这是从列表中获取项目的内部调用 - 所以我认为应该可以正常工作。是否会重构它以用更健谈的方法代替询问,然后回复将是一种直接的行为 - 对吗?
    • 是的。听起来差不多。你发现你的问题了吗?
    • @Dantar - 我正在进行重构,可能很快会有更新,但现在从询问转为告知 - 处理速度提高了 30%
    • 嗯仍然有异常..还有死信通知
    • 嗯仍然有异常..还有死信通知[WARNING][15/02/2016 12:06:45][Thread 0008][akka://test/user/testProbe] DeadLetter from [akka://test/user/$b] to [akka://test/user/testProbe]: &lt;Received dead letter from [akka://test/user/$b]: CollectorActor+ProcessDto&gt;
    【解决方案2】:

    问题在于继承 TestClass 的模拟类,

    决定有“演员系统参考”

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

    但应该是:

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

    这个继承创建了第二个独立的actor系统.....

    感谢@Dantar 的帮助!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-11-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-07-12
      • 2012-07-22
      • 2013-11-29
      相关资源
      最近更新 更多