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

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

问题描述:

我有一个非常简单的FSM成功地做了一个过渡,但不超过。我不知道FSM中是否有错误,或者测试类是否有错误。为什么这个FSM只能在一个状态转换中成功?

这里是单元测试的完整再现的例子:

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
    • 结果:测试通过
    • 输出:N/A
  • 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 BusyBusy => transitioning to Done

我已经通过文档多次了,并不能找到代码中的任何明显的错误。我错过了什么?

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

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

+0

啊,是的,这使它的工作。我在这里省略了一个处理程序,我的实际代码确实在方法中定义了一个处理程序('ConfigureFooStateHandler()'),但我忘记了在构造函数中调用此方法。 – Stijn