为什么这个 FSM 只在一次状态转换中成功?

Why does this FSM only succeed at one state transition?

我有一个非常简单的 FSM,它成功地进行了一次转换,但仅此而已。不知道是FSM有问题还是测试有问题class.

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

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);
    }
}

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

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

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