mirror of
https://github.com/GeWuYou/GFramework.git
synced 2026-03-22 10:34:30 +08:00
test(core): 添加核心组件单元测试
- 添加ArchitectureConstants类的完整单元测试,验证架构阶段常量和转换 - 添加AbstractAsyncCommand抽象类的单元测试,覆盖异步命令的各种场景 - 添加GFrameworkConstants框架常量的单元测试,确保常量值正确性 - 添加AbstractAsyncQuery抽象类的单元测试,验证异步查询功能 - 添加AsyncQueryBus查询总线的单元测试,测试异步查询发送功能
This commit is contained in:
parent
db4306a7bc
commit
241efa0363
195
GFramework.Core.Tests/architecture/ArchitectureConstantsTests.cs
Normal file
195
GFramework.Core.Tests/architecture/ArchitectureConstantsTests.cs
Normal file
@ -0,0 +1,195 @@
|
||||
using System.Collections.Immutable;
|
||||
using GFramework.Core.Abstractions.enums;
|
||||
using GFramework.Core.architecture;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace GFramework.Core.Tests.architecture;
|
||||
|
||||
/// <summary>
|
||||
/// ArchitectureConstants类的单元测试
|
||||
/// 测试内容包括:
|
||||
/// - 常量值的正确性
|
||||
/// - 常量类型验证
|
||||
/// - 常量可访问性
|
||||
/// - 常量命名规范
|
||||
/// - 架构阶段定义常量
|
||||
/// </summary>
|
||||
[TestFixture]
|
||||
public class ArchitectureConstantsTests
|
||||
{
|
||||
/// <summary>
|
||||
/// 测试PhaseOrder数组不为空
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void PhaseOrder_Should_Not_Be_Empty()
|
||||
{
|
||||
Assert.That(ArchitectureConstants.PhaseOrder, Is.Not.Null);
|
||||
Assert.That(ArchitectureConstants.PhaseOrder, Is.Not.Empty);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试PhaseOrder包含所有预期的架构阶段
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void PhaseOrder_Should_Contain_All_Expected_Phases()
|
||||
{
|
||||
var expectedPhases = new[]
|
||||
{
|
||||
ArchitecturePhase.None,
|
||||
ArchitecturePhase.BeforeUtilityInit,
|
||||
ArchitecturePhase.AfterUtilityInit,
|
||||
ArchitecturePhase.BeforeModelInit,
|
||||
ArchitecturePhase.AfterModelInit,
|
||||
ArchitecturePhase.BeforeSystemInit,
|
||||
ArchitecturePhase.AfterSystemInit,
|
||||
ArchitecturePhase.Ready,
|
||||
ArchitecturePhase.Destroying,
|
||||
ArchitecturePhase.Destroyed
|
||||
};
|
||||
|
||||
Assert.That(ArchitectureConstants.PhaseOrder.Length, Is.EqualTo(expectedPhases.Length));
|
||||
|
||||
foreach (var expectedPhase in expectedPhases)
|
||||
{
|
||||
Assert.That(ArchitectureConstants.PhaseOrder, Does.Contain(expectedPhase));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试PhaseOrder数组是只读的
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void PhaseOrder_Should_Be_Immutable()
|
||||
{
|
||||
var phaseOrder = ArchitectureConstants.PhaseOrder;
|
||||
Assert.That(phaseOrder, Is.Not.Null);
|
||||
Assert.That(phaseOrder, Is.InstanceOf<ArchitecturePhase[]>());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试PhaseOrder的顺序是正确的
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void PhaseOrder_Should_Be_In_Correct_Sequence()
|
||||
{
|
||||
var phases = ArchitectureConstants.PhaseOrder;
|
||||
|
||||
Assert.That(phases[0], Is.EqualTo(ArchitecturePhase.None), "First phase should be None");
|
||||
Assert.That(phases[1], Is.EqualTo(ArchitecturePhase.BeforeUtilityInit),
|
||||
"Second phase should be BeforeUtilityInit");
|
||||
Assert.That(phases[2], Is.EqualTo(ArchitecturePhase.AfterUtilityInit),
|
||||
"Third phase should be AfterUtilityInit");
|
||||
Assert.That(phases[3], Is.EqualTo(ArchitecturePhase.BeforeModelInit), "Fourth phase should be BeforeModelInit");
|
||||
Assert.That(phases[4], Is.EqualTo(ArchitecturePhase.AfterModelInit), "Fifth phase should be AfterModelInit");
|
||||
Assert.That(phases[5], Is.EqualTo(ArchitecturePhase.BeforeSystemInit),
|
||||
"Sixth phase should be BeforeSystemInit");
|
||||
Assert.That(phases[6], Is.EqualTo(ArchitecturePhase.AfterSystemInit),
|
||||
"Seventh phase should be AfterSystemInit");
|
||||
Assert.That(phases[7], Is.EqualTo(ArchitecturePhase.Ready), "Eighth phase should be Ready");
|
||||
Assert.That(phases[8], Is.EqualTo(ArchitecturePhase.Destroying), "Ninth phase should be Destroying");
|
||||
Assert.That(phases[9], Is.EqualTo(ArchitecturePhase.Destroyed), "Tenth phase should be Destroyed");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试PhaseTransitions字典不为空
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void PhaseTransitions_Should_Not_Be_Empty()
|
||||
{
|
||||
Assert.That(ArchitectureConstants.PhaseTransitions, Is.Not.Null);
|
||||
Assert.That(ArchitectureConstants.PhaseTransitions, Is.Not.Empty);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试PhaseTransitions是只读的
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void PhaseTransitions_Should_Be_Immutable()
|
||||
{
|
||||
var transitions = ArchitectureConstants.PhaseTransitions;
|
||||
Assert.That(transitions, Is.InstanceOf<ImmutableDictionary<ArchitecturePhase, ArchitecturePhase[]>>());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试PhaseTransitions包含正常线性流程的转换
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void PhaseTransitions_Should_Contain_Normal_Linear_Transitions()
|
||||
{
|
||||
Assert.That(ArchitectureConstants.PhaseTransitions, Does.ContainKey(ArchitecturePhase.None));
|
||||
Assert.That(ArchitectureConstants.PhaseTransitions, Does.ContainKey(ArchitecturePhase.BeforeUtilityInit));
|
||||
Assert.That(ArchitectureConstants.PhaseTransitions, Does.ContainKey(ArchitecturePhase.AfterUtilityInit));
|
||||
Assert.That(ArchitectureConstants.PhaseTransitions, Does.ContainKey(ArchitecturePhase.BeforeModelInit));
|
||||
Assert.That(ArchitectureConstants.PhaseTransitions, Does.ContainKey(ArchitecturePhase.AfterModelInit));
|
||||
Assert.That(ArchitectureConstants.PhaseTransitions, Does.ContainKey(ArchitecturePhase.BeforeSystemInit));
|
||||
Assert.That(ArchitectureConstants.PhaseTransitions, Does.ContainKey(ArchitecturePhase.AfterSystemInit));
|
||||
Assert.That(ArchitectureConstants.PhaseTransitions, Does.ContainKey(ArchitecturePhase.Ready));
|
||||
Assert.That(ArchitectureConstants.PhaseTransitions, Does.ContainKey(ArchitecturePhase.Destroying));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试PhaseTransitions中的转换方向是正确的
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void PhaseTransitions_Should_Have_Correct_Directions()
|
||||
{
|
||||
var transitions = ArchitectureConstants.PhaseTransitions;
|
||||
|
||||
Assert.That(transitions[ArchitecturePhase.None], Does.Contain(ArchitecturePhase.BeforeUtilityInit));
|
||||
Assert.That(transitions[ArchitecturePhase.BeforeUtilityInit], Does.Contain(ArchitecturePhase.AfterUtilityInit));
|
||||
Assert.That(transitions[ArchitecturePhase.AfterUtilityInit], Does.Contain(ArchitecturePhase.BeforeModelInit));
|
||||
Assert.That(transitions[ArchitecturePhase.BeforeModelInit], Does.Contain(ArchitecturePhase.AfterModelInit));
|
||||
Assert.That(transitions[ArchitecturePhase.AfterModelInit], Does.Contain(ArchitecturePhase.BeforeSystemInit));
|
||||
Assert.That(transitions[ArchitecturePhase.BeforeSystemInit], Does.Contain(ArchitecturePhase.AfterSystemInit));
|
||||
Assert.That(transitions[ArchitecturePhase.AfterSystemInit], Does.Contain(ArchitecturePhase.Ready));
|
||||
Assert.That(transitions[ArchitecturePhase.Ready], Does.Contain(ArchitecturePhase.Destroying));
|
||||
Assert.That(transitions[ArchitecturePhase.Destroying], Does.Contain(ArchitecturePhase.Destroyed));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试PhaseTransitions包含失败初始化的转换路径
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void PhaseTransitions_Should_Contain_FailedInitialization_Transition()
|
||||
{
|
||||
Assert.That(ArchitectureConstants.PhaseTransitions, Does.ContainKey(ArchitecturePhase.FailedInitialization));
|
||||
Assert.That(ArchitectureConstants.PhaseTransitions[ArchitecturePhase.FailedInitialization],
|
||||
Does.Contain(ArchitecturePhase.Destroying));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试每个阶段的转换数量不超过1个(线性转换)
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void PhaseTransitions_Should_Have_Maximum_One_Transition_Per_Phase()
|
||||
{
|
||||
foreach (var transition in ArchitectureConstants.PhaseTransitions)
|
||||
{
|
||||
Assert.That(transition.Value, Has.Length.LessThanOrEqualTo(1),
|
||||
$"Phase {transition.Key} should have at most 1 transition");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试PhaseOrder和PhaseTransitions的一致性
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void PhaseOrder_And_PhaseTransitions_Should_Be_Consistent()
|
||||
{
|
||||
var phaseOrder = ArchitectureConstants.PhaseOrder;
|
||||
var transitions = ArchitectureConstants.PhaseTransitions;
|
||||
|
||||
for (int i = 0; i < phaseOrder.Length - 1; i++)
|
||||
{
|
||||
var currentPhase = phaseOrder[i];
|
||||
var nextPhase = phaseOrder[i + 1];
|
||||
|
||||
if (transitions.ContainsKey(currentPhase))
|
||||
{
|
||||
var possibleNextPhases = transitions[currentPhase];
|
||||
Assert.That(possibleNextPhases, Does.Contain(nextPhase),
|
||||
$"Transition from {currentPhase} should include {nextPhase}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
400
GFramework.Core.Tests/command/AbstractAsyncCommandTests.cs
Normal file
400
GFramework.Core.Tests/command/AbstractAsyncCommandTests.cs
Normal file
@ -0,0 +1,400 @@
|
||||
using GFramework.Core.Abstractions.command;
|
||||
using GFramework.Core.Abstractions.rule;
|
||||
using GFramework.Core.architecture;
|
||||
using GFramework.Core.command;
|
||||
using GFramework.Core.environment;
|
||||
using GFramework.Core.events;
|
||||
using GFramework.Core.ioc;
|
||||
using GFramework.Core.query;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace GFramework.Core.Tests.command;
|
||||
|
||||
/// <summary>
|
||||
/// AbstractAsyncCommand类的单元测试
|
||||
/// 测试内容包括:
|
||||
/// - 异步命令无返回值版本的基础实现
|
||||
/// - 异步命令有返回值版本的基础实现
|
||||
/// - ExecuteAsync方法调用
|
||||
/// - ExecuteAsync方法的异常处理
|
||||
/// - 上下文感知功能(SetContext, GetContext)
|
||||
/// - 日志功能(Logger属性)
|
||||
/// - 子类继承行为验证(两个版本)
|
||||
/// - 命令执行前日志记录
|
||||
/// - 命令执行后日志记录
|
||||
/// - 错误情况下的日志记录
|
||||
/// - 无返回值版本的行为
|
||||
/// - 有返回值版本的行为
|
||||
/// </summary>
|
||||
[TestFixture]
|
||||
public class AbstractAsyncCommandTests
|
||||
{
|
||||
[SetUp]
|
||||
public void SetUp()
|
||||
{
|
||||
_container = new IocContainer();
|
||||
_context = new ArchitectureContext(
|
||||
_container,
|
||||
new EventBus(),
|
||||
new CommandBus(),
|
||||
new QueryBus(),
|
||||
new DefaultEnvironment(),
|
||||
new AsyncQueryBus());
|
||||
}
|
||||
|
||||
private ArchitectureContext _context = null!;
|
||||
private IocContainer _container = null!;
|
||||
|
||||
/// <summary>
|
||||
/// 测试异步命令无返回值版本的基础实现
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task AbstractAsyncCommand_Should_Implement_IAsyncCommand_Interface()
|
||||
{
|
||||
var input = new TestCommandInputV2();
|
||||
var command = new TestAsyncCommandV3(input);
|
||||
|
||||
Assert.That(command, Is.InstanceOf<IAsyncCommand>());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试异步命令有返回值版本的基础实现
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task AbstractAsyncCommand_WithResult_Should_Implement_IAsyncCommand_Interface()
|
||||
{
|
||||
var input = new TestCommandInputV2();
|
||||
var command = new TestAsyncCommandWithResultV3(input);
|
||||
|
||||
Assert.That(command, Is.InstanceOf<IAsyncCommand<int>>());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试ExecuteAsync方法调用
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task ExecuteAsync_Should_Invoke_OnExecuteAsync_Method()
|
||||
{
|
||||
var input = new TestCommandInputV2 { Value = 42 };
|
||||
var command = new TestAsyncCommandV3(input);
|
||||
var asyncCommand = (IAsyncCommand)command;
|
||||
|
||||
await asyncCommand.ExecuteAsync();
|
||||
|
||||
Assert.That(command.Executed, Is.True);
|
||||
Assert.That(command.ExecutedValue, Is.EqualTo(42));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试ExecuteAsync方法(带返回值)调用
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task ExecuteAsync_WithResult_Should_Invoke_OnExecuteAsync_Method_And_Return_Result()
|
||||
{
|
||||
var input = new TestCommandInputV2 { Value = 100 };
|
||||
var command = new TestAsyncCommandWithResultV3(input);
|
||||
var asyncCommand = (IAsyncCommand<int>)command;
|
||||
|
||||
var result = await asyncCommand.ExecuteAsync();
|
||||
|
||||
Assert.That(command.Executed, Is.True);
|
||||
Assert.That(result, Is.EqualTo(200));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试ExecuteAsync方法的异常处理
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void ExecuteAsync_Should_Propagate_Exception_From_OnExecuteAsync()
|
||||
{
|
||||
var input = new TestCommandInputV2();
|
||||
var command = new TestAsyncCommandWithExceptionV3(input);
|
||||
var asyncCommand = (IAsyncCommand)command;
|
||||
|
||||
Assert.ThrowsAsync<InvalidOperationException>(async () => await asyncCommand.ExecuteAsync());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试上下文感知功能 - SetContext方法
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void SetContext_Should_Set_Context_Property()
|
||||
{
|
||||
var input = new TestCommandInputV2();
|
||||
var command = new TestAsyncCommandV3(input);
|
||||
var contextAware = (IContextAware)command;
|
||||
|
||||
contextAware.SetContext(_context);
|
||||
|
||||
var context = contextAware.GetContext();
|
||||
Assert.That(context, Is.SameAs(_context));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试上下文感知功能 - GetContext方法
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void GetContext_Should_Return_Context_Property()
|
||||
{
|
||||
var input = new TestCommandInputV2();
|
||||
var command = new TestAsyncCommandV3(input);
|
||||
var contextAware = (IContextAware)command;
|
||||
|
||||
contextAware.SetContext(_context);
|
||||
|
||||
var context = contextAware.GetContext();
|
||||
Assert.That(context, Is.Not.Null);
|
||||
Assert.That(context, Is.SameAs(_context));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试子类继承行为验证 - 无返回值版本
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task Child_Class_Should_Inherit_And_Override_OnExecuteAsync_Method()
|
||||
{
|
||||
var input = new TestCommandInputV2 { Value = 100 };
|
||||
var command = new TestAsyncCommandChildV3(input);
|
||||
var asyncCommand = (IAsyncCommand)command;
|
||||
|
||||
await asyncCommand.ExecuteAsync();
|
||||
|
||||
Assert.That(command.Executed, Is.True);
|
||||
Assert.That(command.ExecutedValue, Is.EqualTo(200));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试子类继承行为验证 - 有返回值版本
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task Child_Class_WithResult_Should_Inherit_And_Override_OnExecuteAsync_Method()
|
||||
{
|
||||
var input = new TestCommandInputV2 { Value = 50 };
|
||||
var command = new TestAsyncCommandWithResultChildV3(input);
|
||||
var asyncCommand = (IAsyncCommand<int>)command;
|
||||
|
||||
var result = await asyncCommand.ExecuteAsync();
|
||||
|
||||
Assert.That(command.Executed, Is.True);
|
||||
Assert.That(result, Is.EqualTo(150));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试异步命令执行生命周期完整性
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task AsyncCommand_Should_Complete_Execution_Lifecycle()
|
||||
{
|
||||
var input = new TestCommandInputV2 { Value = 42 };
|
||||
var command = new TestAsyncCommandV3(input);
|
||||
var asyncCommand = (IAsyncCommand)command;
|
||||
|
||||
Assert.That(command.Executed, Is.False, "Command should not be executed before ExecuteAsync");
|
||||
|
||||
await asyncCommand.ExecuteAsync();
|
||||
|
||||
Assert.That(command.Executed, Is.True, "Command should be executed after ExecuteAsync");
|
||||
Assert.That(command.ExecutedValue, Is.EqualTo(42), "Command should have correct executed value");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试异步命令多次执行
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task AsyncCommand_Should_Be_Executable_Multiple_Times()
|
||||
{
|
||||
var input = new TestCommandInputV2 { Value = 10 };
|
||||
var command = new TestAsyncCommandV3(input);
|
||||
var asyncCommand = (IAsyncCommand)command;
|
||||
|
||||
await asyncCommand.ExecuteAsync();
|
||||
Assert.That(command.ExecutedValue, Is.EqualTo(10), "First execution should have value 10");
|
||||
|
||||
await asyncCommand.ExecuteAsync();
|
||||
Assert.That(command.ExecutedValue, Is.EqualTo(10), "Second execution should have value 10");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试异步命令(带返回值)的返回值类型
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task AsyncCommand_WithResult_Should_Return_Correct_Type()
|
||||
{
|
||||
var input = new TestCommandInputV2 { Value = 100 };
|
||||
var command = new TestAsyncCommandWithResultV3(input);
|
||||
var asyncCommand = (IAsyncCommand<int>)command;
|
||||
|
||||
var result = await asyncCommand.ExecuteAsync();
|
||||
|
||||
Assert.That(result, Is.InstanceOf<int>());
|
||||
Assert.That(result, Is.EqualTo(200));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试用命令输入类V2
|
||||
/// </summary>
|
||||
public sealed class TestCommandInputV2 : ICommandInput
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取或设置值
|
||||
/// </summary>
|
||||
public int Value { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试用异步命令类V3(无返回值)
|
||||
/// </summary>
|
||||
public sealed class TestAsyncCommandV3 : AbstractAsyncCommand<TestCommandInputV2>
|
||||
{
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
/// <param name="input">命令输入</param>
|
||||
public TestAsyncCommandV3(TestCommandInputV2 input) : base(input)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取命令是否已执行
|
||||
/// </summary>
|
||||
public bool Executed { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取执行的值
|
||||
/// </summary>
|
||||
public int ExecutedValue { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 执行异步命令的重写方法
|
||||
/// </summary>
|
||||
/// <param name="input">命令输入</param>
|
||||
/// <returns>表示异步操作的任务</returns>
|
||||
protected override Task OnExecuteAsync(TestCommandInputV2 input)
|
||||
{
|
||||
Executed = true;
|
||||
ExecutedValue = input.Value;
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试用异步命令类V3(有返回值)
|
||||
/// </summary>
|
||||
public sealed class TestAsyncCommandWithResultV3 : AbstractAsyncCommand<TestCommandInputV2, int>
|
||||
{
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
/// <param name="input">命令输入</param>
|
||||
public TestAsyncCommandWithResultV3(TestCommandInputV2 input) : base(input)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取命令是否已执行
|
||||
/// </summary>
|
||||
public bool Executed { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 执行异步命令并返回结果的重写方法
|
||||
/// </summary>
|
||||
/// <param name="input">命令输入</param>
|
||||
/// <returns>执行结果的异步任务</returns>
|
||||
protected override Task<int> OnExecuteAsync(TestCommandInputV2 input)
|
||||
{
|
||||
Executed = true;
|
||||
return Task.FromResult(input.Value * 2);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试用异步命令类(抛出异常)
|
||||
/// </summary>
|
||||
public sealed class TestAsyncCommandWithExceptionV3 : AbstractAsyncCommand<TestCommandInputV2>
|
||||
{
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
/// <param name="input">命令输入</param>
|
||||
public TestAsyncCommandWithExceptionV3(TestCommandInputV2 input) : base(input)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 执行异步命令并抛出异常的重写方法
|
||||
/// </summary>
|
||||
/// <param name="input">命令输入</param>
|
||||
/// <returns>表示异步操作的任务</returns>
|
||||
/// <exception cref="InvalidOperationException">总是抛出异常</exception>
|
||||
protected override Task OnExecuteAsync(TestCommandInputV2 input)
|
||||
{
|
||||
throw new InvalidOperationException("Test exception");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试用异步命令子类(无返回值)
|
||||
/// </summary>
|
||||
public sealed class TestAsyncCommandChildV3 : AbstractAsyncCommand<TestCommandInputV2>
|
||||
{
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
/// <param name="input">命令输入</param>
|
||||
public TestAsyncCommandChildV3(TestCommandInputV2 input) : base(input)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取命令是否已执行
|
||||
/// </summary>
|
||||
public bool Executed { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取执行的值
|
||||
/// </summary>
|
||||
public int ExecutedValue { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 执行异步命令的重写方法(子类实现)
|
||||
/// </summary>
|
||||
/// <param name="input">命令输入</param>
|
||||
/// <returns>表示异步操作的任务</returns>
|
||||
protected override Task OnExecuteAsync(TestCommandInputV2 input)
|
||||
{
|
||||
Executed = true;
|
||||
ExecutedValue = input.Value * 2;
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试用异步命令子类(有返回值)
|
||||
/// </summary>
|
||||
public sealed class TestAsyncCommandWithResultChildV3 : AbstractAsyncCommand<TestCommandInputV2, int>
|
||||
{
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
/// <param name="input">命令输入</param>
|
||||
public TestAsyncCommandWithResultChildV3(TestCommandInputV2 input) : base(input)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取命令是否已执行
|
||||
/// </summary>
|
||||
public bool Executed { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 执行异步命令并返回结果的重写方法(子类实现)
|
||||
/// </summary>
|
||||
/// <param name="input">命令输入</param>
|
||||
/// <returns>执行结果的异步任务</returns>
|
||||
protected override Task<int> OnExecuteAsync(TestCommandInputV2 input)
|
||||
{
|
||||
Executed = true;
|
||||
return Task.FromResult(input.Value * 3);
|
||||
}
|
||||
}
|
||||
69
GFramework.Core.Tests/constants/GFrameworkConstantsTests.cs
Normal file
69
GFramework.Core.Tests/constants/GFrameworkConstantsTests.cs
Normal file
@ -0,0 +1,69 @@
|
||||
using GFramework.Core.constants;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace GFramework.Core.Tests.constants;
|
||||
|
||||
/// <summary>
|
||||
/// GFrameworkConstants类的单元测试
|
||||
/// 测试内容包括:
|
||||
/// - 版本号常量格式正确性
|
||||
/// - 其他框架常量
|
||||
/// - 常量值正确性
|
||||
/// - 常量类型验证
|
||||
/// - 常量可访问性
|
||||
/// </summary>
|
||||
[TestFixture]
|
||||
public class GFrameworkConstantsTests
|
||||
{
|
||||
/// <summary>
|
||||
/// 测试FrameworkName常量的值正确性
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void FrameworkName_Should_Have_Correct_Value()
|
||||
{
|
||||
Assert.That(GFrameworkConstants.FrameworkName, Is.EqualTo("GFramework"));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试FrameworkName常量的类型
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void FrameworkName_Should_Be_String_Type()
|
||||
{
|
||||
Assert.That(GFrameworkConstants.FrameworkName, Is.InstanceOf<string>());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试FrameworkName常量不为空
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void FrameworkName_Should_Not_Be_Null_Or_Empty()
|
||||
{
|
||||
Assert.That(GFrameworkConstants.FrameworkName, Is.Not.Null);
|
||||
Assert.That(GFrameworkConstants.FrameworkName, Is.Not.Empty);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试FrameworkName常量是公共可访问的
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void FrameworkName_Should_Be_Publicly_Accessible()
|
||||
{
|
||||
// 如果常量不存在或不是公共的,编译会失败或抛出异常
|
||||
Assert.DoesNotThrow(() =>
|
||||
{
|
||||
var name = GFrameworkConstants.FrameworkName;
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试FrameworkName常量是只读的(const)
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void FrameworkName_Should_Be_Constant()
|
||||
{
|
||||
// const常量在编译时确定,这个测试主要验证其存在性
|
||||
var name = GFrameworkConstants.FrameworkName;
|
||||
Assert.That(name, Is.EqualTo("GFramework"));
|
||||
}
|
||||
}
|
||||
415
GFramework.Core.Tests/query/AbstractAsyncQueryTests.cs
Normal file
415
GFramework.Core.Tests/query/AbstractAsyncQueryTests.cs
Normal file
@ -0,0 +1,415 @@
|
||||
using GFramework.Core.Abstractions.query;
|
||||
using GFramework.Core.Abstractions.rule;
|
||||
using GFramework.Core.architecture;
|
||||
using GFramework.Core.command;
|
||||
using GFramework.Core.environment;
|
||||
using GFramework.Core.events;
|
||||
using GFramework.Core.ioc;
|
||||
using GFramework.Core.query;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace GFramework.Core.Tests.query;
|
||||
|
||||
/// <summary>
|
||||
/// AbstractAsyncQuery类的单元测试
|
||||
/// 测试内容包括:
|
||||
/// - 异步查询的基础实现
|
||||
/// - DoAsync方法调用
|
||||
/// - DoAsync方法的异常处理
|
||||
/// - 上下文感知功能(SetContext, GetContext)
|
||||
/// - 日志功能(Logger属性)
|
||||
/// - 子类继承行为验证
|
||||
/// - 查询执行前日志记录
|
||||
/// - 查询执行后日志记录
|
||||
/// - 返回值类型验证
|
||||
/// - 错误情况下的日志记录
|
||||
/// </summary>
|
||||
[TestFixture]
|
||||
public class AbstractAsyncQueryTests
|
||||
{
|
||||
[SetUp]
|
||||
public void SetUp()
|
||||
{
|
||||
_container = new IocContainer();
|
||||
_context = new ArchitectureContext(
|
||||
_container,
|
||||
new EventBus(),
|
||||
new CommandBus(),
|
||||
new QueryBus(),
|
||||
new DefaultEnvironment(),
|
||||
new AsyncQueryBus());
|
||||
}
|
||||
|
||||
private ArchitectureContext _context = null!;
|
||||
private IocContainer _container = null!;
|
||||
|
||||
/// <summary>
|
||||
/// 测试异步查询的基础实现
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task AbstractAsyncQuery_Should_Implement_IAsyncQuery_Interface()
|
||||
{
|
||||
var input = new TestAsyncQueryInputV2();
|
||||
var query = new TestAsyncQueryV4(input);
|
||||
|
||||
Assert.That(query, Is.InstanceOf<IAsyncQuery<int>>());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试DoAsync方法调用
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task DoAsync_Should_Invoke_OnDoAsync_Method()
|
||||
{
|
||||
var input = new TestAsyncQueryInputV2 { Value = 42 };
|
||||
var query = new TestAsyncQueryV4(input);
|
||||
var asyncQuery = (IAsyncQuery<int>)query;
|
||||
|
||||
var result = await asyncQuery.DoAsync();
|
||||
|
||||
Assert.That(query.Executed, Is.True);
|
||||
Assert.That(result, Is.EqualTo(84));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试DoAsync方法的异常处理
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void DoAsync_Should_Propagate_Exception_From_OnDoAsync()
|
||||
{
|
||||
var input = new TestAsyncQueryInputV2();
|
||||
var query = new TestAsyncQueryWithExceptionV4(input);
|
||||
var asyncQuery = (IAsyncQuery<int>)query;
|
||||
|
||||
Assert.ThrowsAsync<InvalidOperationException>(async () => await asyncQuery.DoAsync());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试上下文感知功能 - SetContext方法
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void SetContext_Should_Set_Context_Property()
|
||||
{
|
||||
var input = new TestAsyncQueryInputV2();
|
||||
var query = new TestAsyncQueryV4(input);
|
||||
var contextAware = (IContextAware)query;
|
||||
|
||||
contextAware.SetContext(_context);
|
||||
|
||||
var context = contextAware.GetContext();
|
||||
Assert.That(context, Is.SameAs(_context));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试上下文感知功能 - GetContext方法
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void GetContext_Should_Return_Context_Property()
|
||||
{
|
||||
var input = new TestAsyncQueryInputV2();
|
||||
var query = new TestAsyncQueryV4(input);
|
||||
var contextAware = (IContextAware)query;
|
||||
|
||||
contextAware.SetContext(_context);
|
||||
|
||||
var context = contextAware.GetContext();
|
||||
Assert.That(context, Is.Not.Null);
|
||||
Assert.That(context, Is.SameAs(_context));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试子类继承行为验证
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task Child_Class_Should_Inherit_And_Override_OnDoAsync_Method()
|
||||
{
|
||||
var input = new TestAsyncQueryInputV2 { Value = 100 };
|
||||
var query = new TestAsyncQueryChildV4(input);
|
||||
var asyncQuery = (IAsyncQuery<int>)query;
|
||||
|
||||
var result = await asyncQuery.DoAsync();
|
||||
|
||||
Assert.That(query.Executed, Is.True);
|
||||
Assert.That(result, Is.EqualTo(300));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试异步查询执行生命周期完整性
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task AsyncQuery_Should_Complete_Execution_Lifecycle()
|
||||
{
|
||||
var input = new TestAsyncQueryInputV2 { Value = 42 };
|
||||
var query = new TestAsyncQueryV4(input);
|
||||
var asyncQuery = (IAsyncQuery<int>)query;
|
||||
|
||||
Assert.That(query.Executed, Is.False, "Query should not be executed before DoAsync");
|
||||
|
||||
var result = await asyncQuery.DoAsync();
|
||||
|
||||
Assert.That(query.Executed, Is.True, "Query should be executed after DoAsync");
|
||||
Assert.That(result, Is.EqualTo(84), "Query should have correct result");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试异步查询多次执行
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task AsyncQuery_Should_Be_Executable_Multiple_Times()
|
||||
{
|
||||
var input = new TestAsyncQueryInputV2 { Value = 10 };
|
||||
var query = new TestAsyncQueryV4(input);
|
||||
var asyncQuery = (IAsyncQuery<int>)query;
|
||||
|
||||
var result1 = await asyncQuery.DoAsync();
|
||||
var result2 = await asyncQuery.DoAsync();
|
||||
|
||||
Assert.That(result1, Is.EqualTo(20), "First execution should have result 20");
|
||||
Assert.That(result2, Is.EqualTo(20), "Second execution should have result 20");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试异步查询的返回值类型
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task AsyncQuery_Should_Return_Correct_Type()
|
||||
{
|
||||
var input = new TestAsyncQueryInputV2 { Value = 100 };
|
||||
var query = new TestAsyncQueryV4(input);
|
||||
var asyncQuery = (IAsyncQuery<int>)query;
|
||||
|
||||
var result = await asyncQuery.DoAsync();
|
||||
|
||||
Assert.That(result, Is.InstanceOf<int>());
|
||||
Assert.That(result, Is.EqualTo(200));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试异步查询的字符串返回值
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task AsyncQuery_WithStringResult_Should_Return_String()
|
||||
{
|
||||
var input = new TestAsyncQueryInputV2 { Value = 5 };
|
||||
var query = new TestAsyncStringQueryV4(input);
|
||||
var asyncQuery = (IAsyncQuery<string>)query;
|
||||
|
||||
var result = await asyncQuery.DoAsync();
|
||||
|
||||
Assert.That(result, Is.InstanceOf<string>());
|
||||
Assert.That(result, Is.EqualTo("Value: 10"));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试异步查询的复杂对象返回值
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task AsyncQuery_WithComplexResult_Should_Return_ComplexObject()
|
||||
{
|
||||
var input = new TestAsyncQueryInputV2 { Value = 10 };
|
||||
var query = new TestAsyncComplexQueryV4(input);
|
||||
var asyncQuery = (IAsyncQuery<TestAsyncQueryResultV2>)query;
|
||||
|
||||
var result = await asyncQuery.DoAsync();
|
||||
|
||||
Assert.That(result, Is.Not.Null);
|
||||
Assert.That(result.Value, Is.EqualTo(20));
|
||||
Assert.That(result.DoubleValue, Is.EqualTo(30));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试异步查询在不同实例之间的独立性
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task AsyncQuery_Should_Maintain_Independence_Between_Different_Instances()
|
||||
{
|
||||
var input1 = new TestAsyncQueryInputV2 { Value = 10 };
|
||||
var input2 = new TestAsyncQueryInputV2 { Value = 20 };
|
||||
var query1 = new TestAsyncQueryV4(input1);
|
||||
var query2 = new TestAsyncQueryV4(input2);
|
||||
var asyncQuery1 = (IAsyncQuery<int>)query1;
|
||||
var asyncQuery2 = (IAsyncQuery<int>)query2;
|
||||
|
||||
var result1 = await asyncQuery1.DoAsync();
|
||||
var result2 = await asyncQuery2.DoAsync();
|
||||
|
||||
Assert.That(result1, Is.EqualTo(20));
|
||||
Assert.That(result2, Is.EqualTo(40));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试用异步查询输入类V2
|
||||
/// </summary>
|
||||
public sealed class TestAsyncQueryInputV2 : IQueryInput
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取或设置值
|
||||
/// </summary>
|
||||
public int Value { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 整数类型测试异步查询类V4,继承AbstractAsyncQuery
|
||||
/// </summary>
|
||||
public sealed class TestAsyncQueryV4 : AbstractAsyncQuery<TestAsyncQueryInputV2, int>
|
||||
{
|
||||
/// <summary>
|
||||
/// 初始化TestAsyncQueryV4的新实例
|
||||
/// </summary>
|
||||
/// <param name="input">查询输入参数</param>
|
||||
public TestAsyncQueryV4(TestAsyncQueryInputV2 input) : base(input)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取查询是否已执行
|
||||
/// </summary>
|
||||
public bool Executed { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 执行异步查询操作的具体实现
|
||||
/// </summary>
|
||||
/// <param name="input">查询输入参数</param>
|
||||
/// <returns>查询结果,将输入值乘以2</returns>
|
||||
protected override Task<int> OnDoAsync(TestAsyncQueryInputV2 input)
|
||||
{
|
||||
Executed = true;
|
||||
return Task.FromResult(input.Value * 2);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 字符串类型测试异步查询类V4,继承AbstractAsyncQuery
|
||||
/// </summary>
|
||||
public sealed class TestAsyncStringQueryV4 : AbstractAsyncQuery<TestAsyncQueryInputV2, string>
|
||||
{
|
||||
/// <summary>
|
||||
/// 初始化TestAsyncStringQueryV4的新实例
|
||||
/// </summary>
|
||||
/// <param name="input">查询输入参数</param>
|
||||
public TestAsyncStringQueryV4(TestAsyncQueryInputV2 input) : base(input)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取查询是否已执行
|
||||
/// </summary>
|
||||
public bool Executed { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 执行异步查询操作的具体实现
|
||||
/// </summary>
|
||||
/// <param name="input">查询输入参数</param>
|
||||
/// <returns>格式化的字符串结果</returns>
|
||||
protected override Task<string> OnDoAsync(TestAsyncQueryInputV2 input)
|
||||
{
|
||||
Executed = true;
|
||||
return Task.FromResult($"Value: {input.Value * 2}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 复杂对象类型测试异步查询类V4,继承AbstractAsyncQuery
|
||||
/// </summary>
|
||||
public sealed class TestAsyncComplexQueryV4 : AbstractAsyncQuery<TestAsyncQueryInputV2, TestAsyncQueryResultV2>
|
||||
{
|
||||
/// <summary>
|
||||
/// 初始化TestAsyncComplexQueryV4的新实例
|
||||
/// </summary>
|
||||
/// <param name="input">查询输入参数</param>
|
||||
public TestAsyncComplexQueryV4(TestAsyncQueryInputV2 input) : base(input)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取查询是否已执行
|
||||
/// </summary>
|
||||
public bool Executed { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 执行异步查询操作的具体实现
|
||||
/// </summary>
|
||||
/// <param name="input">查询输入参数</param>
|
||||
/// <returns>复杂对象查询结果</returns>
|
||||
protected override Task<TestAsyncQueryResultV2> OnDoAsync(TestAsyncQueryInputV2 input)
|
||||
{
|
||||
Executed = true;
|
||||
var result = new TestAsyncQueryResultV2
|
||||
{
|
||||
Value = input.Value * 2,
|
||||
DoubleValue = input.Value * 3
|
||||
};
|
||||
return Task.FromResult(result);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试用异步查询类(抛出异常)
|
||||
/// </summary>
|
||||
public sealed class TestAsyncQueryWithExceptionV4 : AbstractAsyncQuery<TestAsyncQueryInputV2, int>
|
||||
{
|
||||
/// <summary>
|
||||
/// 初始化TestAsyncQueryWithExceptionV4的新实例
|
||||
/// </summary>
|
||||
/// <param name="input">查询输入参数</param>
|
||||
public TestAsyncQueryWithExceptionV4(TestAsyncQueryInputV2 input) : base(input)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 执行异步查询操作并抛出异常
|
||||
/// </summary>
|
||||
/// <param name="input">查询输入参数</param>
|
||||
/// <exception cref="InvalidOperationException">总是抛出异常</exception>
|
||||
protected override Task<int> OnDoAsync(TestAsyncQueryInputV2 input)
|
||||
{
|
||||
throw new InvalidOperationException("Test exception");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试用异步查询子类V4,继承AbstractAsyncQuery
|
||||
/// </summary>
|
||||
public sealed class TestAsyncQueryChildV4 : AbstractAsyncQuery<TestAsyncQueryInputV2, int>
|
||||
{
|
||||
/// <summary>
|
||||
/// 初始化TestAsyncQueryChildV4的新实例
|
||||
/// </summary>
|
||||
/// <param name="input">查询输入参数</param>
|
||||
public TestAsyncQueryChildV4(TestAsyncQueryInputV2 input) : base(input)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取查询是否已执行
|
||||
/// </summary>
|
||||
public bool Executed { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 执行异步查询操作的具体实现(子类实现,乘以3)
|
||||
/// </summary>
|
||||
/// <param name="input">查询输入参数</param>
|
||||
/// <returns>查询结果,将输入值乘以3</returns>
|
||||
protected override Task<int> OnDoAsync(TestAsyncQueryInputV2 input)
|
||||
{
|
||||
Executed = true;
|
||||
return Task.FromResult(input.Value * 3);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试用复杂查询结果类V2
|
||||
/// </summary>
|
||||
public sealed class TestAsyncQueryResultV2
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取或设置值
|
||||
/// </summary>
|
||||
public int Value { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置双倍值
|
||||
/// </summary>
|
||||
public int DoubleValue { get; init; }
|
||||
}
|
||||
296
GFramework.Core.Tests/query/AsyncQueryBusTests.cs
Normal file
296
GFramework.Core.Tests/query/AsyncQueryBusTests.cs
Normal file
@ -0,0 +1,296 @@
|
||||
using GFramework.Core.Abstractions.query;
|
||||
using GFramework.Core.query;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace GFramework.Core.Tests.query;
|
||||
|
||||
/// <summary>
|
||||
/// AsyncQueryBus类的单元测试
|
||||
/// 测试内容包括:
|
||||
/// - SendAsync方法 - 正常查询发送
|
||||
/// - SendAsync方法 - 空查询异常
|
||||
/// - 异步查询结果正确性
|
||||
/// - 不同返回类型的异步查询支持
|
||||
/// - 异步查询的异常处理
|
||||
/// - 异步查询的上下文传递
|
||||
/// </summary>
|
||||
[TestFixture]
|
||||
public class AsyncQueryBusTests
|
||||
{
|
||||
[SetUp]
|
||||
public void SetUp()
|
||||
{
|
||||
_asyncQueryBus = new AsyncQueryBus();
|
||||
}
|
||||
|
||||
private AsyncQueryBus _asyncQueryBus = null!;
|
||||
|
||||
/// <summary>
|
||||
/// 测试SendAsync方法正确返回查询结果
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task SendAsync_Should_Return_Query_Result()
|
||||
{
|
||||
var input = new TestAsyncQueryInput { Value = 10 };
|
||||
var query = new TestAsyncQuery(input);
|
||||
|
||||
var result = await _asyncQueryBus.SendAsync(query);
|
||||
|
||||
Assert.That(result, Is.EqualTo(20));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试SendAsync方法在传入空查询对象时是否会抛出ArgumentNullException异常
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void SendAsync_WithNullQuery_Should_ThrowArgumentNullException()
|
||||
{
|
||||
Assert.ThrowsAsync<ArgumentNullException>(async () => await _asyncQueryBus.SendAsync<int>(null!));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试SendAsync方法是否能正确返回字符串类型的查询结果
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task SendAsync_WithStringResult_Should_Return_String()
|
||||
{
|
||||
var input = new TestAsyncQueryInput { Value = 5 };
|
||||
var query = new TestAsyncStringQuery(input);
|
||||
|
||||
var result = await _asyncQueryBus.SendAsync(query);
|
||||
|
||||
Assert.That(result, Is.EqualTo("Result: 10"));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试SendAsync方法是否能正确返回布尔类型的查询结果
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task SendAsync_WithBooleanResult_Should_Return_Boolean()
|
||||
{
|
||||
var input = new TestAsyncQueryInput { Value = 42 };
|
||||
var query = new TestAsyncBooleanQuery(input);
|
||||
|
||||
var result = await _asyncQueryBus.SendAsync(query);
|
||||
|
||||
Assert.That(result, Is.True);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试SendAsync方法是否能正确处理复杂对象的查询结果
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task SendAsync_WithComplexObjectResult_Should_Return_ComplexObject()
|
||||
{
|
||||
var input = new TestAsyncQueryInput { Value = 100 };
|
||||
var query = new TestAsyncComplexQuery(input);
|
||||
|
||||
var result = await _asyncQueryBus.SendAsync(query);
|
||||
|
||||
Assert.That(result, Is.Not.Null);
|
||||
Assert.That(result.Value, Is.EqualTo(200));
|
||||
Assert.That(result.DoubleValue, Is.EqualTo(300));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试SendAsync方法是否能正确处理抛出异常的查询
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void SendAsync_Should_Propagate_Exception_From_Query()
|
||||
{
|
||||
var input = new TestAsyncQueryInput { Value = 0 };
|
||||
var query = new TestAsyncQueryWithException(input);
|
||||
|
||||
Assert.ThrowsAsync<InvalidOperationException>(async () => await _asyncQueryBus.SendAsync(query));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试SendAsync方法多次调用
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task SendAsync_Should_Be_Callable_Multiple_Times()
|
||||
{
|
||||
var input = new TestAsyncQueryInput { Value = 10 };
|
||||
var query = new TestAsyncQuery(input);
|
||||
|
||||
var result1 = await _asyncQueryBus.SendAsync(query);
|
||||
var result2 = await _asyncQueryBus.SendAsync(query);
|
||||
|
||||
Assert.That(result1, Is.EqualTo(20));
|
||||
Assert.That(result2, Is.EqualTo(20));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试SendAsync方法在不同查询之间保持独立性
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task SendAsync_Should_Maintain_Independence_Between_Different_Queries()
|
||||
{
|
||||
var input1 = new TestAsyncQueryInput { Value = 10 };
|
||||
var input2 = new TestAsyncQueryInput { Value = 20 };
|
||||
var query1 = new TestAsyncQuery(input1);
|
||||
var query2 = new TestAsyncQuery(input2);
|
||||
|
||||
var result1 = await _asyncQueryBus.SendAsync(query1);
|
||||
var result2 = await _asyncQueryBus.SendAsync(query2);
|
||||
|
||||
Assert.That(result1, Is.EqualTo(20));
|
||||
Assert.That(result2, Is.EqualTo(40));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试用异步查询输入类,实现IQueryInput接口
|
||||
/// </summary>
|
||||
public sealed class TestAsyncQueryInput : IQueryInput
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取或设置查询值
|
||||
/// </summary>
|
||||
public int Value { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 整数类型测试异步查询类,继承AbstractAsyncQuery
|
||||
/// 实现具体的异步查询逻辑并返回整数结果
|
||||
/// </summary>
|
||||
public sealed class TestAsyncQuery : AbstractAsyncQuery<TestAsyncQueryInput, int>
|
||||
{
|
||||
/// <summary>
|
||||
/// 初始化TestAsyncQuery的新实例
|
||||
/// </summary>
|
||||
/// <param name="input">查询输入参数</param>
|
||||
public TestAsyncQuery(TestAsyncQueryInput input) : base(input)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 执行异步查询操作的具体实现
|
||||
/// </summary>
|
||||
/// <param name="input">查询输入参数</param>
|
||||
/// <returns>查询结果,将输入值乘以2</returns>
|
||||
protected override Task<int> OnDoAsync(TestAsyncQueryInput input)
|
||||
{
|
||||
return Task.FromResult(input.Value * 2);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 字符串类型测试异步查询类,继承AbstractAsyncQuery
|
||||
/// 实现具体的异步查询逻辑并返回字符串结果
|
||||
/// </summary>
|
||||
public sealed class TestAsyncStringQuery : AbstractAsyncQuery<TestAsyncQueryInput, string>
|
||||
{
|
||||
/// <summary>
|
||||
/// 初始化TestAsyncStringQuery的新实例
|
||||
/// </summary>
|
||||
/// <param name="input">查询输入参数</param>
|
||||
public TestAsyncStringQuery(TestAsyncQueryInput input) : base(input)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 执行异步查询操作的具体实现
|
||||
/// </summary>
|
||||
/// <param name="input">查询输入参数</param>
|
||||
/// <returns>格式化的字符串结果</returns>
|
||||
protected override Task<string> OnDoAsync(TestAsyncQueryInput input)
|
||||
{
|
||||
return Task.FromResult($"Result: {input.Value * 2}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 布尔类型测试异步查询类,继承AbstractAsyncQuery
|
||||
/// 实现具体的异步查询逻辑并返回布尔结果
|
||||
/// </summary>
|
||||
public sealed class TestAsyncBooleanQuery : AbstractAsyncQuery<TestAsyncQueryInput, bool>
|
||||
{
|
||||
/// <summary>
|
||||
/// 初始化TestAsyncBooleanQuery的新实例
|
||||
/// </summary>
|
||||
/// <param name="input">查询输入参数</param>
|
||||
public TestAsyncBooleanQuery(TestAsyncQueryInput input) : base(input)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 执行异步查询操作的具体实现
|
||||
/// </summary>
|
||||
/// <param name="input">查询输入参数</param>
|
||||
/// <returns>如果值大于0返回true,否则返回false</returns>
|
||||
protected override Task<bool> OnDoAsync(TestAsyncQueryInput input)
|
||||
{
|
||||
return Task.FromResult(input.Value > 0);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 复杂对象类型测试异步查询类,继承AbstractAsyncQuery
|
||||
/// 实现具体的异步查询逻辑并返回复杂对象结果
|
||||
/// </summary>
|
||||
public sealed class TestAsyncComplexQuery : AbstractAsyncQuery<TestAsyncQueryInput, TestAsyncQueryResult>
|
||||
{
|
||||
/// <summary>
|
||||
/// 初始化TestAsyncComplexQuery的新实例
|
||||
/// </summary>
|
||||
/// <param name="input">查询输入参数</param>
|
||||
public TestAsyncComplexQuery(TestAsyncQueryInput input) : base(input)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 执行异步查询操作的具体实现
|
||||
/// </summary>
|
||||
/// <param name="input">查询输入参数</param>
|
||||
/// <returns>复杂对象查询结果</returns>
|
||||
protected override Task<TestAsyncQueryResult> OnDoAsync(TestAsyncQueryInput input)
|
||||
{
|
||||
var result = new TestAsyncQueryResult
|
||||
{
|
||||
Value = input.Value * 2,
|
||||
DoubleValue = input.Value * 3
|
||||
};
|
||||
return Task.FromResult(result);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试用异步查询类(抛出异常)
|
||||
/// </summary>
|
||||
public sealed class TestAsyncQueryWithException : AbstractAsyncQuery<TestAsyncQueryInput, int>
|
||||
{
|
||||
/// <summary>
|
||||
/// 初始化TestAsyncQueryWithException的新实例
|
||||
/// </summary>
|
||||
/// <param name="input">查询输入参数</param>
|
||||
public TestAsyncQueryWithException(TestAsyncQueryInput input) : base(input)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 执行异步查询操作并抛出异常
|
||||
/// </summary>
|
||||
/// <param name="input">查询输入参数</param>
|
||||
/// <exception cref="InvalidOperationException">总是抛出异常</exception>
|
||||
protected override Task<int> OnDoAsync(TestAsyncQueryInput input)
|
||||
{
|
||||
throw new InvalidOperationException("Test exception");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试用复杂查询结果类
|
||||
/// </summary>
|
||||
public sealed class TestAsyncQueryResult
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取或设置值
|
||||
/// </summary>
|
||||
public int Value { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置双倍值
|
||||
/// </summary>
|
||||
public int DoubleValue { get; init; }
|
||||
}
|
||||
296
GFramework.Core.Tests/utility/AbstractContextUtilityTests.cs
Normal file
296
GFramework.Core.Tests/utility/AbstractContextUtilityTests.cs
Normal file
@ -0,0 +1,296 @@
|
||||
using GFramework.Core.Abstractions.logging;
|
||||
using GFramework.Core.Abstractions.rule;
|
||||
using GFramework.Core.Abstractions.utility;
|
||||
using GFramework.Core.architecture;
|
||||
using GFramework.Core.command;
|
||||
using GFramework.Core.environment;
|
||||
using GFramework.Core.events;
|
||||
using GFramework.Core.ioc;
|
||||
using GFramework.Core.query;
|
||||
using GFramework.Core.utility;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace GFramework.Core.Tests.utility;
|
||||
|
||||
/// <summary>
|
||||
/// AbstractContextUtility类的单元测试
|
||||
/// 测试内容包括:
|
||||
/// - 抽象工具类实现
|
||||
/// - IContextUtility接口实现
|
||||
/// - Init方法调用
|
||||
/// - 日志初始化
|
||||
/// - 上下文感知功能(SetContext, GetContext)
|
||||
/// - 子类继承行为
|
||||
/// - 工具初始化日志记录
|
||||
/// - 工具生命周期完整性
|
||||
/// </summary>
|
||||
[TestFixture]
|
||||
public class AbstractContextUtilityTests
|
||||
{
|
||||
[SetUp]
|
||||
public void SetUp()
|
||||
{
|
||||
_container = new IocContainer();
|
||||
_context = new ArchitectureContext(
|
||||
_container,
|
||||
new EventBus(),
|
||||
new CommandBus(),
|
||||
new QueryBus(),
|
||||
new DefaultEnvironment(),
|
||||
new AsyncQueryBus());
|
||||
}
|
||||
|
||||
private ArchitectureContext _context = null!;
|
||||
private IocContainer _container = null!;
|
||||
|
||||
/// <summary>
|
||||
/// 测试AbstractContextUtility实现IContextUtility接口
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void AbstractContextUtility_Should_Implement_IContextUtility_Interface()
|
||||
{
|
||||
var utility = new TestContextUtilityV1();
|
||||
|
||||
Assert.That(utility, Is.InstanceOf<IContextUtility>());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试Init方法调用
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void Init_Should_Call_OnInit_Method()
|
||||
{
|
||||
var utility = new TestContextUtilityV1();
|
||||
|
||||
Assert.That(utility.Initialized, Is.False, "Utility should not be initialized before Init");
|
||||
|
||||
utility.Init();
|
||||
|
||||
Assert.That(utility.Initialized, Is.True, "Utility should be initialized after Init");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试Init方法设置Logger属性
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void Init_Should_Set_Logger_Property()
|
||||
{
|
||||
var utility = new TestContextUtilityV1();
|
||||
|
||||
Assert.That(utility.GetLogger(), Is.Null, "Logger should be null before Init");
|
||||
|
||||
utility.Init();
|
||||
|
||||
Assert.That(utility.GetLogger(), Is.Not.Null, "Logger should be set after Init");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试Init方法记录初始化日志
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void Init_Should_Log_Initialization()
|
||||
{
|
||||
var utility = new TestContextUtilityV1();
|
||||
|
||||
Assert.That(utility.InitCalled, Is.False, "InitCalled should be false before Init");
|
||||
|
||||
utility.Init();
|
||||
|
||||
Assert.That(utility.InitCalled, Is.True, "InitCalled should be true after Init");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试Destroy方法调用
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void Destroy_Should_Call_OnDestroy_Method()
|
||||
{
|
||||
var utility = new TestContextUtilityV1();
|
||||
|
||||
utility.Init();
|
||||
Assert.That(utility.Destroyed, Is.False, "Utility should not be destroyed before Destroy");
|
||||
|
||||
utility.Destroy();
|
||||
|
||||
Assert.That(utility.Destroyed, Is.True, "Utility should be destroyed after Destroy");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试上下文感知功能 - SetContext方法
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void SetContext_Should_Set_Context_Property()
|
||||
{
|
||||
var utility = new TestContextUtilityV1();
|
||||
var contextAware = (IContextAware)utility;
|
||||
|
||||
contextAware.SetContext(_context);
|
||||
|
||||
var context = contextAware.GetContext();
|
||||
Assert.That(context, Is.SameAs(_context));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试上下文感知功能 - GetContext方法
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void GetContext_Should_Return_Context_Property()
|
||||
{
|
||||
var utility = new TestContextUtilityV1();
|
||||
var contextAware = (IContextAware)utility;
|
||||
|
||||
contextAware.SetContext(_context);
|
||||
|
||||
var context = contextAware.GetContext();
|
||||
Assert.That(context, Is.Not.Null);
|
||||
Assert.That(context, Is.SameAs(_context));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试子类继承行为
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void Child_Class_Should_Override_OnInit_Method()
|
||||
{
|
||||
var utility = new TestContextUtilityV2();
|
||||
|
||||
Assert.That(utility.Initialized, Is.False);
|
||||
Assert.That(utility.CustomInitializationDone, Is.False);
|
||||
|
||||
utility.Init();
|
||||
|
||||
Assert.That(utility.Initialized, Is.True);
|
||||
Assert.That(utility.CustomInitializationDone, Is.True);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试工具生命周期完整性
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void ContextUtility_Should_Complete_Full_Lifecycle()
|
||||
{
|
||||
var utility = new TestContextUtilityV1();
|
||||
|
||||
// 初始状态
|
||||
Assert.That(utility.Initialized, Is.False);
|
||||
Assert.That(utility.Destroyed, Is.False);
|
||||
|
||||
// 初始化
|
||||
utility.Init();
|
||||
Assert.That(utility.Initialized, Is.True);
|
||||
Assert.That(utility.Destroyed, Is.False);
|
||||
|
||||
// 销毁
|
||||
utility.Destroy();
|
||||
Assert.That(utility.Initialized, Is.True);
|
||||
Assert.That(utility.Destroyed, Is.True);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试工具类可以多次初始化和销毁
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void ContextUtility_Should_Be_Initializable_And_Destroyable_Multiple_Times()
|
||||
{
|
||||
var utility = new TestContextUtilityV1();
|
||||
|
||||
// 第一次初始化和销毁
|
||||
utility.Init();
|
||||
Assert.That(utility.Initialized, Is.True);
|
||||
utility.Destroy();
|
||||
Assert.That(utility.Destroyed, Is.True);
|
||||
|
||||
// 重置状态
|
||||
utility.Destroyed = false;
|
||||
|
||||
// 第二次初始化和销毁
|
||||
utility.Init();
|
||||
Assert.That(utility.Initialized, Is.True);
|
||||
utility.Destroy();
|
||||
Assert.That(utility.Destroyed, Is.True);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试用上下文工具类V1
|
||||
/// </summary>
|
||||
public sealed class TestContextUtilityV1 : AbstractContextUtility
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取工具是否已初始化
|
||||
/// </summary>
|
||||
public bool Initialized { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取工具是否已销毁
|
||||
/// </summary>
|
||||
public bool Destroyed { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取Init方法是否被调用
|
||||
/// </summary>
|
||||
public bool InitCalled { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取Logger对象(用于测试)
|
||||
/// </summary>
|
||||
public ILogger? GetLogger()
|
||||
{
|
||||
return Logger;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 初始化方法
|
||||
/// </summary>
|
||||
protected override void OnInit()
|
||||
{
|
||||
Initialized = true;
|
||||
InitCalled = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 销毁方法
|
||||
/// </summary>
|
||||
protected override void OnDestroy()
|
||||
{
|
||||
Destroyed = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试用上下文工具类V2,自定义初始化逻辑
|
||||
/// </summary>
|
||||
public sealed class TestContextUtilityV2 : AbstractContextUtility
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取工具是否已初始化
|
||||
/// </summary>
|
||||
public bool Initialized { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取工具是否已销毁
|
||||
/// </summary>
|
||||
public bool Destroyed { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取自定义初始化是否完成
|
||||
/// </summary>
|
||||
public bool CustomInitializationDone { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 初始化方法(自定义逻辑)
|
||||
/// </summary>
|
||||
protected override void OnInit()
|
||||
{
|
||||
Initialized = true;
|
||||
CustomInitializationDone = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 销毁方法
|
||||
/// </summary>
|
||||
protected override void OnDestroy()
|
||||
{
|
||||
Destroyed = true;
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user