我有一个非常简单的 FSM,它成功地完成了一次转换,但仅此而已。不知道是FSM有错误还是test类有错误。

这是一个带有单元测试的完全可重现的示例:

using Akka;
using Akka.Actor;
using Akka.TestKit;
using Akka.TestKit.Xunit;
using System.Diagnostics;
using Xunit;

class MyFsm : FSM<MyFsm.State, MyFsm.Data>
{
    public MyFsm()
    {
        StartWith(State.Idle, new Data());

        When(State.Idle, state =>
        {
            var eventWasHandled = state.FsmEvent.Match()
                .With<MessageA>(message => { return; })
                .WasHandled;

            if (eventWasHandled)
            {
                Debug.WriteLine($"{State.Idle} => transitioning to {State.Busy}");
                return GoTo(State.Busy);
            }
            else
            {
                Debug.WriteLine($"{State.Idle} => returning null");
                return null;
            }
        });

        When(State.Busy, state =>
        {
            var eventWasHandled = state.FsmEvent.Match()
                .With<MessageB>(message => { return; })
                .WasHandled;

            if (eventWasHandled)
            {
                Debug.WriteLine($"{State.Busy} => transitioning to {State.Done}");
                return GoTo(State.Done);
            }
            else
            {
                Debug.WriteLine($"{State.Busy} => returning null");
                return null;
            }
        });

        Initialize();
    }

    public enum State { Idle, Busy, Done }

    public class Data { }
}

class MessageA { }

class MessageB { }

public class MyFsmTests : TestKit
{
    [Fact]
    public void Its_initial_state_is_Idle()
    {
        var myFsm = new TestFSMRef<MyFsm, MyFsm.State, MyFsm.Data>(Sys, Props.Create<MyFsm>());

        Assert.Equal(MyFsm.State.Idle, myFsm.StateName);
    }

    [Fact]
    public void It_transitions_to_the_Busy_state_after_receiving_MessageA()
    {
        var myFsm = new TestFSMRef<MyFsm, MyFsm.State, MyFsm.Data>(Sys, Props.Create<MyFsm>());
        myFsm.SetState(MyFsm.State.Idle);

        myFsm.Tell(new MessageA());

        Assert.Equal(MyFsm.State.Busy, myFsm.StateName);
    }

    [Fact]
    public void It_transitions_to_the_Done_state_after_receiving_MessageB_using_SetState()
    {
        var myFsm = new TestFSMRef<MyFsm, MyFsm.State, MyFsm.Data>(Sys, Props.Create<MyFsm>());
        myFsm.SetState(MyFsm.State.Busy);

        myFsm.Tell(new MessageB());

        Assert.Equal(MyFsm.State.Done, myFsm.StateName);
    }

    [Fact]
    public void It_transitions_to_the_Done_state_after_receiving_MessageB_without_using_SetState()
    {
        var myFsm = new TestFSMRef<MyFsm, MyFsm.State, MyFsm.Data>(Sys, Props.Create<MyFsm>());

        myFsm.Tell(new MessageA());
        myFsm.Tell(new MessageB());

        Assert.Equal(MyFsm.State.Done, myFsm.StateName);
    }
}
  • its_initial_state_is_Idle
  • 结果:测试通过
  • 输出:不适用
  • It_transitions_to_the_Busy_state_after_receiving_MessageA
  • 结果:测试通过
  • 输出:Idle => transitioning to Busy
  • It_transitions_to_the_Done_state_after_receiving_MessageB_using_SetState
  • 结果:测试失败 Assert.Equal() Failure Expected: Done Actual: Busy
  • 输出:Busy => transitioning to Done
  • It_transitions_to_the_Done_state_after_receiving_MessageB_without_using_SetState
  • 结果:测试失败 Assert.Equal() Failure Expected: Done Actual: Busy
  • 输出:Idle => transitioning to Busy Busy => transitioning to Done

  • 我已经多次浏览文档,但在代码中找不到任何明显的错误。我错过了什么?

    最佳答案

    看起来这里的问题是您实际上没有定义为 Done 的状态,据 FSM 所知。

    您需要添加一个 When(State.Done, e => { ... }) 处理程序,这将允许 FSM 转换到该行为并正确报告它。

    关于c# - 为什么这个 FSM 只在一个状态转换时成功?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/46588702/

    10-13 06:04