GFramework/GFramework.Core.Tests/state/StateMachineTests.cs
GeWuYou b49079de3e style(coding-style): 统一代码风格并优化文档格式
- 移除多余using语句和空行,统一代码缩进格式
- 优化注释文档中的缩进和对齐格式
- 简化条件语句和方法实现,提升代码可读性
- 重构协程系统相关类的字段和方法定义格式
- 更新架构服务中容器访问方式的实现
- 调整异步操作类的属性和方法组织结构
- [skip ci]
2026-01-27 20:30:04 +08:00

444 lines
13 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System.Reflection;
using GFramework.Core.Abstractions.state;
using GFramework.Core.state;
using NUnit.Framework;
namespace GFramework.Core.Tests.state;
/// <summary>
/// 测试状态机功能的单元测试类
/// </summary>
[TestFixture]
public class StateMachineTests
{
/// <summary>
/// 在每个测试方法执行前初始化状态机实例
/// </summary>
[SetUp]
public void SetUp()
{
_stateMachine = new StateMachine();
}
private StateMachine _stateMachine = null!;
/// <summary>
/// 验证当没有活动状态时当前状态应为null
/// </summary>
[Test]
public void Current_Should_BeNull_When_NoState_Active()
{
Assert.That(_stateMachine.Current, Is.Null);
}
/// <summary>
/// 验证注册状态后,状态会被添加到状态字典中
/// </summary>
[Test]
public void Register_Should_AddState_To_StatesDictionary()
{
var state = new TestStateV2();
_stateMachine.Register(state);
Assert.That(_stateMachine.ContainsState<TestStateV2>(), Is.True);
}
/// <summary>
/// 验证ChangeTo方法能够正确设置当前状态
/// </summary>
[Test]
public void ChangeTo_Should_SetCurrentState()
{
var state = new TestStateV2();
_stateMachine.Register(state);
_stateMachine.ChangeTo<TestStateV2>();
Assert.That(_stateMachine.Current, Is.SameAs(state));
}
/// <summary>
/// 验证ChangeTo方法会调用OnEnter回调
/// </summary>
[Test]
public void ChangeTo_Should_Invoke_OnEnter()
{
var state = new TestStateV2();
_stateMachine.Register(state);
_stateMachine.ChangeTo<TestStateV2>();
Assert.That(state.EnterCalled, Is.True);
Assert.That(state.EnterFrom, Is.Null);
}
/// <summary>
/// 验证当存在当前状态时切换到新状态会调用原状态的OnExit回调
/// </summary>
[Test]
public void ChangeTo_When_CurrentStateExists_Should_Invoke_OnExit()
{
var state1 = new TestStateV2();
var state2 = new TestStateV3();
_stateMachine.Register(state1);
_stateMachine.Register(state2);
_stateMachine.ChangeTo<TestStateV2>();
_stateMachine.ChangeTo<TestStateV3>();
Assert.That(state1.ExitCalled, Is.True);
Assert.That(state1.ExitTo, Is.SameAs(state2));
}
/// <summary>
/// 验证当存在当前状态时切换到新状态会调用新状态的OnEnter回调
/// </summary>
[Test]
public void ChangeTo_When_CurrentStateExists_Should_Invoke_OnEnter()
{
var state1 = new TestStateV2();
var state2 = new TestStateV3();
_stateMachine.Register(state1);
_stateMachine.Register(state2);
_stateMachine.ChangeTo<TestStateV2>();
_stateMachine.ChangeTo<TestStateV3>();
Assert.That(state2.EnterCalled, Is.True);
Assert.That(state2.EnterFrom, Is.SameAs(state1));
}
/// <summary>
/// 验证切换到相同状态时不应调用回调方法
/// </summary>
[Test]
public void ChangeTo_ToSameState_Should_NotInvoke_Callbacks()
{
var state = new TestStateV2();
_stateMachine.Register(state);
_stateMachine.ChangeTo<TestStateV2>();
var enterCount = state.EnterCallCount;
var exitCount = state.ExitCallCount;
_stateMachine.ChangeTo<TestStateV2>();
Assert.That(state.EnterCallCount, Is.EqualTo(enterCount));
Assert.That(state.ExitCallCount, Is.EqualTo(exitCount));
}
/// <summary>
/// 验证切换到未注册状态时应抛出InvalidOperationException异常
/// </summary>
[Test]
public void ChangeTo_ToUnregisteredState_Should_ThrowInvalidOperationException()
{
Assert.Throws<InvalidOperationException>(() => _stateMachine.ChangeTo<TestStateV2>());
}
/// <summary>
/// 验证当状态未注册时CanChangeTo方法应返回false
/// </summary>
[Test]
public void CanChangeTo_WhenStateNotRegistered_Should_ReturnFalse()
{
var result = _stateMachine.CanChangeTo<TestStateV2>();
Assert.That(result, Is.False);
}
/// <summary>
/// 验证当状态已注册时CanChangeTo方法应返回true
/// </summary>
[Test]
public void CanChangeTo_WhenStateRegistered_Should_ReturnTrue()
{
var state = new TestStateV2();
_stateMachine.Register(state);
var result = _stateMachine.CanChangeTo<TestStateV2>();
Assert.That(result, Is.True);
}
/// <summary>
/// 验证当当前状态拒绝转换时CanChangeTo方法应返回false
/// </summary>
[Test]
public void CanChangeTo_WhenCurrentStateDeniesTransition_Should_ReturnFalse()
{
var state1 = new TestStateV2 { AllowTransition = false };
var state2 = new TestStateV3();
_stateMachine.Register(state1);
_stateMachine.Register(state2);
_stateMachine.ChangeTo<TestStateV2>();
var result = _stateMachine.CanChangeTo<TestStateV3>();
Assert.That(result, Is.False);
}
/// <summary>
/// 验证当当前状态拒绝转换时不应发生状态变化
/// </summary>
[Test]
public void ChangeTo_WhenCurrentStateDeniesTransition_Should_NotChange()
{
var state1 = new TestStateV2 { AllowTransition = false };
var state2 = new TestStateV3();
_stateMachine.Register(state1);
_stateMachine.Register(state2);
_stateMachine.ChangeTo<TestStateV2>();
var oldState = _stateMachine.Current;
var result = _stateMachine.ChangeTo<TestStateV3>();
Assert.That(result, Is.False);
Assert.That(_stateMachine.Current, Is.SameAs(oldState));
Assert.That(_stateMachine.Current, Is.SameAs(state1));
Assert.That(state2.EnterCalled, Is.False);
}
/// <summary>
/// 验证注销状态后应从字典中移除该状态
/// </summary>
[Test]
public void Unregister_Should_RemoveState_FromDictionary()
{
var state = new TestStateV2();
_stateMachine.Register(state);
_stateMachine.Unregister<TestStateV2>();
Assert.That(_stateMachine.ContainsState<TestStateV2>(), Is.False);
}
/// <summary>
/// 验证当活动状态被注销时应调用OnExit并清除当前状态
/// </summary>
[Test]
public void Unregister_WhenStateIsActive_Should_Invoke_OnExit_AndClearCurrent()
{
var state = new TestStateV2();
_stateMachine.Register(state);
_stateMachine.ChangeTo<TestStateV2>();
_stateMachine.Unregister<TestStateV2>();
Assert.That(state.ExitCalled, Is.True);
Assert.That(state.ExitTo, Is.Null);
Assert.That(_stateMachine.Current, Is.Null);
}
/// <summary>
/// 验证当非活动状态被注销时不应调用OnExit
/// </summary>
[Test]
public void Unregister_WhenStateNotActive_Should_Not_Invoke_OnExit()
{
var state1 = new TestStateV2();
var state2 = new TestStateV3();
_stateMachine.Register(state1);
_stateMachine.Register(state2);
_stateMachine.ChangeTo<TestStateV2>();
_stateMachine.Unregister<TestStateV3>();
Assert.That(state1.ExitCalled, Is.False);
Assert.That(_stateMachine.Current, Is.SameAs(state1));
}
/// <summary>
/// 验证多次状态转换应正确调用回调方法
/// </summary>
[Test]
public void MultipleStateChanges_Should_Invoke_Callbacks_Correctly()
{
var state1 = new TestStateV2();
var state2 = new TestStateV3();
var state3 = new TestStateV4();
_stateMachine.Register(state1);
_stateMachine.Register(state2);
_stateMachine.Register(state3);
_stateMachine.ChangeTo<TestStateV2>();
_stateMachine.ChangeTo<TestStateV3>();
_stateMachine.ChangeTo<TestStateV4>();
Assert.That(state1.EnterCalled, Is.True);
Assert.That(state1.ExitCalled, Is.True);
Assert.That(state2.EnterCalled, Is.True);
Assert.That(state2.ExitCalled, Is.True);
Assert.That(state3.EnterCalled, Is.True);
Assert.That(state3.ExitCalled, Is.False);
}
/// <summary>
/// 验证ChangeTo方法应遵循CanTransitionTo逻辑
/// </summary>
[Test]
public void ChangeTo_Should_Respect_CanTransitionTo_Logic()
{
var state1 = new TestStateV2();
var state2 = new TestStateV3();
var state3 = new TestStateV4();
_stateMachine.Register(state1);
_stateMachine.Register(state2);
_stateMachine.Register(state3);
_stateMachine.ChangeTo<TestStateV2>();
_stateMachine.ChangeTo<TestStateV3>();
Assert.That(state1.EnterCalled, Is.True);
Assert.That(state1.ExitCalled, Is.True);
Assert.That(state2.EnterCalled, Is.True);
}
}
/// <summary>
/// 测试状态类V2版本实现IState接口用于测试
/// </summary>
public sealed class TestStateV2 : IState
{
public bool AllowTransition { get; set; } = true;
public bool EnterCalled { get; private set; }
public bool ExitCalled { get; private set; }
public int EnterCallCount { get; private set; }
public int ExitCallCount { get; private set; }
public IState? EnterFrom { get; private set; }
public IState? ExitTo { get; private set; }
/// <summary>
/// 进入状态时的回调方法
/// </summary>
/// <param name="from">从哪个状态进入</param>
public void OnEnter(IState? from)
{
EnterCalled = true;
EnterCallCount++;
EnterFrom = from;
}
/// <summary>
/// 离开状态时的回调方法
/// </summary>
/// <param name="to">离开到哪个状态</param>
public void OnExit(IState? to)
{
ExitCalled = true;
ExitCallCount++;
ExitTo = to;
}
/// <summary>
/// 判断是否可以转换到目标状态
/// </summary>
/// <param name="target">目标状态</param>
/// <returns>是否允许转换</returns>
public bool CanTransitionTo(IState target)
{
return AllowTransition;
}
}
/// <summary>
/// 测试状态类V3版本实现IState接口用于测试
/// </summary>
public sealed class TestStateV3 : IState
{
public bool EnterCalled { get; private set; }
public bool ExitCalled { get; private set; }
public int EnterCallCount { get; private set; }
public int ExitCallCount { get; private set; }
public IState? EnterFrom { get; private set; }
public IState? ExitTo { get; private set; }
/// <summary>
/// 进入状态时的回调方法
/// </summary>
/// <param name="from">从哪个状态进入</param>
public void OnEnter(IState? from)
{
EnterCalled = true;
EnterCallCount++;
EnterFrom = from;
}
/// <summary>
/// 离开状态时的回调方法
/// </summary>
/// <param name="to">离开到哪个状态</param>
public void OnExit(IState? to)
{
ExitCalled = true;
ExitCallCount++;
ExitTo = to;
}
/// <summary>
/// 判断是否可以转换到目标状态
/// </summary>
/// <param name="target">目标状态</param>
/// <returns>是否允许转换</returns>
public bool CanTransitionTo(IState target)
{
return true;
}
}
/// <summary>
/// 测试状态类V4版本实现IState接口用于测试
/// </summary>
public sealed class TestStateV4 : IState
{
public bool EnterCalled { get; private set; }
public bool ExitCalled { get; private set; }
public int EnterCallCount { get; private set; }
public int ExitCallCount { get; private set; }
public IState? EnterFrom { get; private set; }
public IState? ExitTo { get; private set; }
/// <summary>
/// 进入状态时的回调方法
/// </summary>
/// <param name="from">从哪个状态进入</param>
public void OnEnter(IState? from)
{
EnterCalled = true;
EnterCallCount++;
EnterFrom = from;
}
/// <summary>
/// 离开状态时的回调方法
/// </summary>
/// <param name="to">离开到哪个状态</param>
public void OnExit(IState? to)
{
ExitCalled = true;
ExitCallCount++;
ExitTo = to;
}
/// <summary>
/// 判断是否可以转换到目标状态
/// </summary>
/// <param name="target">目标状态</param>
/// <returns>是否允许转换</returns>
public bool CanTransitionTo(IState target)
{
return true;
}
}
/// <summary>
/// 状态机扩展方法类
/// </summary>
public static class StateMachineExtensions
{
/// <summary>
/// 检查状态机是否包含指定类型的状态
/// </summary>
/// <typeparam name="T">要检查的状态类型</typeparam>
/// <param name="stateMachine">状态机实例</param>
/// <returns>如果包含指定类型的状态则返回true否则返回false</returns>
public static bool ContainsState<T>(this StateMachine stateMachine) where T : IState
{
return stateMachine.GetType().GetField("States", BindingFlags.NonPublic | BindingFlags.Instance)?
.GetValue(stateMachine) is Dictionary<Type, IState> states &&
states.ContainsKey(typeof(T));
}
}