Reputation: 24212
I have a very simple FSM that succeeds at doing one transition, but no more than that. I don't know if there's an error in the FSM or if there's an error in the test class.
Here is a full reproducible example with unit tests:
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);
}
}
Idle => transitioning to Busy
Assert.Equal() Failure Expected: Done Actual: Busy
Busy => transitioning to Done
Assert.Equal() Failure Expected: Done Actual: Busy
Idle => transitioning to Busy
Busy => transitioning to Done
I've gone through the docs multiple times and can't find any glaring error in the code. What am I missing?
Upvotes: 3
Views: 138
Reputation: 8394
Looks like the issue here is that you don't actually have a state defined as Done
, as far as this FSM knows.
You need to add a When(State.Done, e => { ... })
handler and that will allow the FSM to transition to that behavior and report it correctly.
Upvotes: 3