GFramework/GFramework.Cqrs.Tests/Cqrs/AbstractCqrsHandlerContextTests.cs
GeWuYou e36c80229a feat(cqrs): 添加CQRS处理器基类和测试运行时支持
- 引入AbstractCommandHandler、AbstractQueryHandler等各类处理器基类
- 实现CqrsContextAwareHandlerBase提供上下文感知功能
- 添加CqrsTestRuntime为测试项目提供CQRS运行时访问入口
- 创建AbstractCqrsHandlerContextTests验证上下文注入行为
- 支持命令、查询、通知及流式处理的各种抽象基类实现
2026-04-15 20:34:08 +08:00

75 lines
2.5 KiB
C#

using GFramework.Core.Abstractions.Architectures;
using GFramework.Core.Abstractions.Rule;
using GFramework.Cqrs.Abstractions.Cqrs;
using GFramework.Cqrs.Abstractions.Cqrs.Command;
using GFramework.Cqrs.Cqrs.Command;
namespace GFramework.Cqrs.Tests.Cqrs;
/// <summary>
/// 验证 CQRS handler 基类在脱离 dispatcher 使用时会显式失败,并在注入上下文后保持可观察行为。
/// </summary>
[TestFixture]
internal sealed class AbstractCqrsHandlerContextTests
{
/// <summary>
/// 验证新的轻量 handler 基类不会再偷偷回退到全局 GameContext。
/// </summary>
[Test]
public void GetContext_Should_Throw_When_Handler_Has_Not_Been_Initialized_By_Runtime()
{
var handler = new TestCommandHandler();
var exception = Assert.Throws<InvalidOperationException>(() => ((IContextAware)handler).GetContext());
Assert.That(
exception!.Message,
Does.Contain("has not been initialized").IgnoreCase);
}
/// <summary>
/// 验证 runtime 注入上下文后,派生 handler 可以继续访问 Context 并收到 OnContextReady 回调。
/// </summary>
[Test]
public async Task Handle_Should_Observe_Injected_Context_And_OnContextReady_Callback()
{
var handler = new TestCommandHandler();
var context = new Mock<IArchitectureContext>(MockBehavior.Strict).Object;
((IContextAware)handler).SetContext(context);
await handler.Handle(new TestCommand(), CancellationToken.None);
Assert.Multiple(() =>
{
Assert.That(handler.OnContextReadyCallCount, Is.EqualTo(1));
Assert.That(handler.LastObservedContext, Is.SameAs(context));
});
}
/// <summary>
/// 用于验证上下文注入行为的最小 CQRS 命令。
/// </summary>
private sealed record TestCommand : ICommand<Unit>;
/// <summary>
/// 暴露基类上下文访问与初始化回调的测试处理器。
/// </summary>
private sealed class TestCommandHandler : AbstractCommandHandler<TestCommand>
{
public int OnContextReadyCallCount { get; private set; }
public IArchitectureContext? LastObservedContext { get; private set; }
protected override void OnContextReady()
{
OnContextReadyCallCount++;
}
public override ValueTask<Unit> Handle(TestCommand command, CancellationToken cancellationToken)
{
LastObservedContext = Context;
return ValueTask.FromResult(Unit.Value);
}
}
}