为什么这个 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);
}
}
- 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 Busy
Busy => transitioning to Done
我已经多次浏览文档,但在代码中找不到任何明显的错误。我错过了什么?
看起来这里的问题是,据此 FSM 所知,您实际上没有定义为 Done
的状态。
您需要添加一个 When(State.Done, e => { ... })
处理程序,这将允许 FSM 转换到该行为并正确报告它。
我有一个非常简单的 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);
}
}
- 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 Busy
Busy => transitioning to Done
- 结果:测试失败
我已经多次浏览文档,但在代码中找不到任何明显的错误。我错过了什么?
看起来这里的问题是,据此 FSM 所知,您实际上没有定义为 Done
的状态。
您需要添加一个 When(State.Done, e => { ... })
处理程序,这将允许 FSM 转换到该行为并正确报告它。