mirror of
https://github.com/GeWuYou/GFramework.git
synced 2026-03-22 19:03:29 +08:00
- 在ContextAwareExtensions中添加事件发送、注册和取消注册方法 - 添加环境对象获取功能 - 扩展命令和查询功能支持同步、异步及中介者模式 - 添加统一请求处理方法和便捷扩展方法 - 为StateMachineSystem添加异步状态切换事件通知功能 - 添加状态机异步操作相关单元测试 - 扩展现有测试类以覆盖新增功能 - [release ci]
497 lines
14 KiB
C#
497 lines
14 KiB
C#
using System.Reflection;
|
||
using GFramework.Core.Abstractions.enums;
|
||
using GFramework.Core.Abstractions.state;
|
||
using GFramework.Core.Abstractions.system;
|
||
using GFramework.Core.architecture;
|
||
using GFramework.Core.command;
|
||
using GFramework.Core.environment;
|
||
using GFramework.Core.events;
|
||
using GFramework.Core.ioc;
|
||
using GFramework.Core.logging;
|
||
using GFramework.Core.query;
|
||
using GFramework.Core.state;
|
||
using NUnit.Framework;
|
||
|
||
namespace GFramework.Core.Tests.state;
|
||
|
||
/// <summary>
|
||
/// ContextAwareStateMachine类的单元测试
|
||
/// 测试内容包括:
|
||
/// - 作为ISystem的集成测试
|
||
/// - Init方法 - 初始化上下文感知状态
|
||
/// - Init方法 - 设置Context属性
|
||
/// - Destroy方法 - 清理状态
|
||
/// - OnArchitecturePhase方法 - 接收架构阶段
|
||
/// - 上下文感知状态初始化
|
||
/// - 状态变更事件发送
|
||
/// - SetContext方法
|
||
/// - GetContext方法
|
||
/// - ISystem接口实现验证
|
||
/// - 与EventBus的集成测试
|
||
/// - 多状态注册和切换
|
||
/// - 状态机生命周期完整性
|
||
/// </summary>
|
||
[TestFixture]
|
||
public class StateMachineSystemTests
|
||
{
|
||
[SetUp]
|
||
public void SetUp()
|
||
{
|
||
// 初始化 LoggerFactoryResolver 以支持 MicrosoftDiContainer
|
||
LoggerFactoryResolver.Provider = new ConsoleLoggerFactoryProvider();
|
||
|
||
_eventBus = new EventBus();
|
||
var container = new MicrosoftDiContainer();
|
||
|
||
// 直接初始化 logger 字段
|
||
var loggerField = typeof(MicrosoftDiContainer).GetField("_logger",
|
||
BindingFlags.NonPublic | BindingFlags.Instance);
|
||
loggerField?.SetValue(container,
|
||
LoggerFactoryResolver.Provider.CreateLogger(nameof(StateMachineSystemTests)));
|
||
|
||
container.RegisterPlurality(_eventBus);
|
||
container.RegisterPlurality(new CommandExecutor());
|
||
container.RegisterPlurality(new QueryExecutor());
|
||
container.RegisterPlurality(new DefaultEnvironment());
|
||
container.RegisterPlurality(new AsyncQueryExecutor());
|
||
|
||
_context = new ArchitectureContext(container);
|
||
|
||
_stateMachine = new TestStateMachineSystemV5();
|
||
_stateMachine.SetContext(_context);
|
||
}
|
||
|
||
private TestStateMachineSystemV5? _stateMachine;
|
||
private ArchitectureContext? _context;
|
||
private EventBus? _eventBus;
|
||
|
||
/// <summary>
|
||
/// 测试ContextAwareStateMachine实现ISystem接口
|
||
/// </summary>
|
||
[Test]
|
||
public void ContextAwareStateMachine_Should_Implement_ISystem_Interface()
|
||
{
|
||
Assert.That(_stateMachine, Is.InstanceOf<ISystem>());
|
||
}
|
||
|
||
/// <summary>
|
||
/// 测试SetContext设置Context属性
|
||
/// </summary>
|
||
[Test]
|
||
public void SetContext_Should_Set_Context_Property()
|
||
{
|
||
_stateMachine!.SetContext(_context!);
|
||
|
||
var context = _stateMachine.GetContext();
|
||
Assert.That(context, Is.SameAs(_context));
|
||
}
|
||
|
||
/// <summary>
|
||
/// 测试GetContext返回Context属性
|
||
/// </summary>
|
||
[Test]
|
||
public void GetContext_Should_Return_Context_Property()
|
||
{
|
||
_stateMachine!.SetContext(_context!);
|
||
|
||
var context = _stateMachine.GetContext();
|
||
Assert.That(context, Is.Not.Null);
|
||
Assert.That(context, Is.SameAs(_context));
|
||
}
|
||
|
||
/// <summary>
|
||
/// 测试Init方法为所有ContextAware状态设置Context
|
||
/// </summary>
|
||
[Test]
|
||
public void Init_Should_SetContext_On_All_ContextAware_States()
|
||
{
|
||
var state1 = new TestContextAwareStateV5();
|
||
var state2 = new TestContextAwareStateV5_2();
|
||
|
||
_stateMachine!.Register(state1);
|
||
_stateMachine.Register(state2);
|
||
|
||
Assert.Throws<InvalidOperationException>(() => state1.GetContext());
|
||
Assert.Throws<InvalidOperationException>(() => state2.GetContext());
|
||
|
||
_stateMachine.Init();
|
||
|
||
Assert.That(state1.GetContext(), Is.SameAs(_context));
|
||
Assert.That(state2.GetContext(), Is.SameAs(_context));
|
||
}
|
||
|
||
/// <summary>
|
||
/// 测试Init方法不为非ContextAware状态设置Context
|
||
/// </summary>
|
||
[Test]
|
||
public void Init_Should_Not_SetContext_On_NonContextAware_States()
|
||
{
|
||
var state = new TestStateV5();
|
||
|
||
_stateMachine!.Register(state);
|
||
_stateMachine.Init();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 测试Destroy方法不抛出异常
|
||
/// </summary>
|
||
[Test]
|
||
public void Destroy_Should_Not_Throw_Exception()
|
||
{
|
||
Assert.That(() => _stateMachine!.Destroy(), Throws.Nothing);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 测试OnArchitecturePhase方法不抛出异常
|
||
/// </summary>
|
||
[Test]
|
||
public void OnArchitecturePhase_Should_Not_Throw_Exception()
|
||
{
|
||
Assert.That(() => _stateMachine!.OnArchitecturePhase(ArchitecturePhase.Ready),
|
||
Throws.Nothing);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 测试ChangeTo发送StateChangedEvent事件
|
||
/// 验证当状态机切换到新状态时,会正确触发StateChangedEvent事件,并且事件中的旧状态为null(首次切换)
|
||
/// </summary>
|
||
[Test]
|
||
public void ChangeTo_Should_Send_StateChangedEvent()
|
||
{
|
||
// 订阅StateChangedEvent事件以验证事件是否被正确发送
|
||
var eventReceived = false;
|
||
StateChangedEvent? receivedEvent = null;
|
||
|
||
_eventBus!.Register<StateChangedEvent>(e =>
|
||
{
|
||
eventReceived = true;
|
||
receivedEvent = e;
|
||
});
|
||
|
||
var state1 = new TestStateV5();
|
||
var state2 = new TestStateV5();
|
||
|
||
_stateMachine!.Register(state1);
|
||
_stateMachine.Register(state2);
|
||
|
||
_stateMachine.Init();
|
||
_stateMachine.ChangeTo<TestStateV5>();
|
||
|
||
Assert.That(eventReceived, Is.True);
|
||
Assert.That(receivedEvent!.OldState, Is.Null);
|
||
Assert.That(receivedEvent.NewState, Is.InstanceOf<TestStateV5>());
|
||
}
|
||
|
||
/// <summary>
|
||
/// 测试ChangeTo发送StateChangedEvent事件(包含旧状态)
|
||
/// 验证当状态机从一个状态切换到另一个状态时,会正确触发StateChangedEvent事件,
|
||
/// 并且事件中包含正确的旧状态和新状态信息
|
||
/// </summary>
|
||
[Test]
|
||
public void ChangeTo_Should_Send_StateChangedEvent_With_OldState()
|
||
{
|
||
// 订阅StateChangedEvent事件以验证事件是否被正确发送
|
||
var eventReceived = false;
|
||
StateChangedEvent? receivedEvent = null;
|
||
|
||
_eventBus!.Register<StateChangedEvent>(e =>
|
||
{
|
||
eventReceived = true;
|
||
receivedEvent = e;
|
||
});
|
||
|
||
var state1 = new TestStateV5();
|
||
var state2 = new TestStateV5();
|
||
|
||
_stateMachine!.Register(state1);
|
||
_stateMachine.Register(state2);
|
||
|
||
_stateMachine.Init();
|
||
_stateMachine.ChangeTo<TestStateV5>();
|
||
_stateMachine.ChangeTo<TestStateV5>();
|
||
|
||
Assert.That(eventReceived, Is.True);
|
||
Assert.That(receivedEvent!.OldState, Is.InstanceOf<TestStateV5>());
|
||
Assert.That(receivedEvent.NewState, Is.InstanceOf<TestStateV5>());
|
||
}
|
||
|
||
/// <summary>
|
||
/// 测试CanChangeTo方法对于已注册状态的工作情况
|
||
/// 验证当状态已注册到状态机中时,CanChangeTo方法应返回true
|
||
/// </summary>
|
||
[Test]
|
||
public void CanChangeTo_Should_Work_With_Registered_States()
|
||
{
|
||
var state = new TestStateV5();
|
||
|
||
_stateMachine!.Register(state);
|
||
|
||
var canChange = _stateMachine.CanChangeTo<TestStateV5>();
|
||
Assert.That(canChange, Is.True);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 测试可以注册多个状态
|
||
/// 验证状态机能够成功注册多个不同的状态实例,并且能够切换到这些已注册的状态
|
||
/// </summary>
|
||
[Test]
|
||
public void Multiple_States_Should_Be_Registered()
|
||
{
|
||
var state1 = new TestStateV5 { Id = 1 };
|
||
var state2 = new TestStateV5 { Id = 2 };
|
||
var state3 = new TestStateV5 { Id = 3 };
|
||
|
||
_stateMachine!.Register(state1);
|
||
_stateMachine.Register(state2);
|
||
_stateMachine.Register(state3);
|
||
|
||
var canChange = _stateMachine.CanChangeTo<TestStateV5>();
|
||
Assert.That(canChange, Is.True);
|
||
}
|
||
|
||
|
||
/// <summary>
|
||
/// 测试状态机生命周期完整
|
||
/// </summary>
|
||
[Test]
|
||
public void StateMachine_Lifecycle_Should_Be_Complete()
|
||
{
|
||
var state1 = new TestStateV5();
|
||
var state2 = new TestStateV5();
|
||
|
||
_stateMachine!.Register(state1);
|
||
_stateMachine.Register(state2);
|
||
|
||
_stateMachine.Init();
|
||
Assert.That(_stateMachine.Current, Is.Null);
|
||
|
||
_stateMachine.ChangeTo<TestStateV5>();
|
||
Assert.That(_stateMachine.Current, Is.InstanceOf<TestStateV5>());
|
||
|
||
_stateMachine.Destroy();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 测试异步ChangeToAsync发送StateChangedEvent事件
|
||
/// 验证当状态机使用异步方法切换到新状态时,会正确触发StateChangedEvent事件
|
||
/// </summary>
|
||
[Test]
|
||
public async Task ChangeToAsync_Should_Send_StateChangedEvent()
|
||
{
|
||
var eventReceived = false;
|
||
StateChangedEvent? receivedEvent = null;
|
||
|
||
_eventBus!.Register<StateChangedEvent>(e =>
|
||
{
|
||
eventReceived = true;
|
||
receivedEvent = e;
|
||
});
|
||
|
||
var state1 = new TestStateV5();
|
||
var state2 = new TestStateV5();
|
||
|
||
_stateMachine!.Register(state1);
|
||
_stateMachine.Register(state2);
|
||
|
||
_stateMachine.Init();
|
||
await _stateMachine.ChangeToAsync<TestStateV5>();
|
||
|
||
Assert.That(eventReceived, Is.True);
|
||
Assert.That(receivedEvent!.OldState, Is.Null);
|
||
Assert.That(receivedEvent.NewState, Is.InstanceOf<TestStateV5>());
|
||
}
|
||
|
||
/// <summary>
|
||
/// 测试异步ChangeToAsync发送StateChangedEvent事件(包含旧状态)
|
||
/// 验证当状态机使用异步方法从一个状态切换到另一个状态时,会正确触发StateChangedEvent事件
|
||
/// </summary>
|
||
[Test]
|
||
public async Task ChangeToAsync_Should_Send_StateChangedEvent_With_OldState()
|
||
{
|
||
var eventReceived = false;
|
||
StateChangedEvent? receivedEvent = null;
|
||
|
||
_eventBus!.Register<StateChangedEvent>(e =>
|
||
{
|
||
eventReceived = true;
|
||
receivedEvent = e;
|
||
});
|
||
|
||
var state1 = new TestStateV5();
|
||
var state2 = new TestStateV5_2();
|
||
|
||
_stateMachine!.Register(state1);
|
||
_stateMachine.Register(state2);
|
||
|
||
_stateMachine.Init();
|
||
await _stateMachine.ChangeToAsync<TestStateV5>();
|
||
|
||
eventReceived = false;
|
||
await _stateMachine.ChangeToAsync<TestStateV5_2>();
|
||
|
||
Assert.That(eventReceived, Is.True);
|
||
Assert.That(receivedEvent!.OldState, Is.InstanceOf<TestStateV5>());
|
||
Assert.That(receivedEvent.NewState, Is.InstanceOf<TestStateV5_2>());
|
||
}
|
||
|
||
/// <summary>
|
||
/// 测试异步切换时多次状态变更都能正确触发事件
|
||
/// </summary>
|
||
[Test]
|
||
public async Task ChangeToAsync_MultipleChanges_Should_Send_Events_Correctly()
|
||
{
|
||
var eventCount = 0;
|
||
|
||
_eventBus!.Register<StateChangedEvent>(_ => { eventCount++; });
|
||
|
||
var state1 = new TestStateV5();
|
||
var state2 = new TestStateV5_2();
|
||
|
||
_stateMachine!.Register(state1);
|
||
_stateMachine.Register(state2);
|
||
|
||
_stateMachine.Init();
|
||
await _stateMachine.ChangeToAsync<TestStateV5>();
|
||
await _stateMachine.ChangeToAsync<TestStateV5_2>();
|
||
await _stateMachine.ChangeToAsync<TestStateV5>();
|
||
|
||
Assert.That(eventCount, Is.EqualTo(3));
|
||
}
|
||
}
|
||
|
||
#region Test Classes
|
||
|
||
/// <summary>
|
||
/// 测试用的ContextAwareStateMachine派生类,用于访问内部状态字典
|
||
/// </summary>
|
||
public class TestStateMachineSystemV5 : StateMachineSystem
|
||
{
|
||
/// <summary>
|
||
/// 获取状态机内部的状态字典
|
||
/// </summary>
|
||
/// <returns>类型到状态实例的映射字典</returns>
|
||
public Dictionary<Type, IState> GetStates()
|
||
{
|
||
return States;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 测试用的上下文感知状态基类实现
|
||
/// </summary>
|
||
public class TestContextAwareStateV5 : ContextAwareStateBase
|
||
{
|
||
/// <summary>
|
||
/// 进入状态时调用
|
||
/// </summary>
|
||
/// <param name="previous">前一个状态</param>
|
||
public override void OnEnter(IState? previous)
|
||
{
|
||
}
|
||
|
||
/// <summary>
|
||
/// 退出状态时调用
|
||
/// </summary>
|
||
/// <param name="next">下一个状态</param>
|
||
public override void OnExit(IState? next)
|
||
{
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 第二个测试用的上下文感知状态基类实现
|
||
/// </summary>
|
||
public class TestContextAwareStateV5_2 : ContextAwareStateBase
|
||
{
|
||
/// <summary>
|
||
/// 进入状态时调用
|
||
/// </summary>
|
||
/// <param name="previous">前一个状态</param>
|
||
public override void OnEnter(IState? previous)
|
||
{
|
||
}
|
||
|
||
/// <summary>
|
||
/// 退出状态时调用
|
||
/// </summary>
|
||
/// <param name="next">下一个状态</param>
|
||
public override void OnExit(IState? next)
|
||
{
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 测试用的普通状态实现
|
||
/// </summary>
|
||
public class TestStateV5 : IState
|
||
{
|
||
/// <summary>
|
||
/// 状态标识符
|
||
/// </summary>
|
||
public int Id { get; set; }
|
||
|
||
/// <summary>
|
||
/// 检查是否可以转换到指定状态
|
||
/// </summary>
|
||
/// <param name="next">目标状态</param>
|
||
/// <returns>始终返回true表示允许转换</returns>
|
||
public bool CanTransitionTo(IState next)
|
||
{
|
||
return true;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 进入状态时调用
|
||
/// </summary>
|
||
/// <param name="previous">前一个状态</param>
|
||
public void OnEnter(IState? previous)
|
||
{
|
||
}
|
||
|
||
/// <summary>
|
||
/// 退出状态时调用
|
||
/// </summary>
|
||
/// <param name="next">下一个状态</param>
|
||
public void OnExit(IState? next)
|
||
{
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 第二个测试用的普通状态实现,用于区分不同状态类型
|
||
/// </summary>
|
||
public class TestStateV5_2 : IState
|
||
{
|
||
/// <summary>
|
||
/// 状态标识符
|
||
/// </summary>
|
||
public int Id { get; set; }
|
||
|
||
/// <summary>
|
||
/// 检查是否可以转换到指定状态
|
||
/// </summary>
|
||
/// <param name="next">目标状态</param>
|
||
/// <returns>始终返回true表示允许转换</returns>
|
||
public bool CanTransitionTo(IState next)
|
||
{
|
||
return true;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 进入状态时调用
|
||
/// </summary>
|
||
/// <param name="previous">前一个状态</param>
|
||
public void OnEnter(IState? previous)
|
||
{
|
||
}
|
||
|
||
/// <summary>
|
||
/// 退出状态时调用
|
||
/// </summary>
|
||
/// <param name="next">下一个状态</param>
|
||
public void OnExit(IState? next)
|
||
{
|
||
}
|
||
}
|
||
|
||
#endregion |