From ec8f72932b1d16c24ce0534640fe79f36aafd4ec Mon Sep 17 00:00:00 2001
From: GeWuYou <95328647+GeWuYou@users.noreply.github.com>
Date: Sun, 1 Feb 2026 11:04:50 +0800
Subject: [PATCH] =?UTF-8?q?test(coroutine):=20=E6=B7=BB=E5=8A=A0=E5=8D=8F?=
=?UTF-8?q?=E7=A8=8B=E7=9B=B8=E5=85=B3=E5=8A=9F=E8=83=BD=E7=9A=84=E5=8D=95?=
=?UTF-8?q?=E5=85=83=E6=B5=8B=E8=AF=95?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 添加 CommandCoroutineExtensions 的完整测试用例
- 添加 QueryCoroutineExtensions 的完整测试用例
- 添加 WaitForEvent 的完整测试用例
- 添加 WaitForEventWithTimeout 的完整测试用例
- 添加 Moq 依赖包用于模拟测试
- 实现多种协程指令和扩展方法的功能验证
- 包含超时处理、异常处理和事件触发等场景测试
- [release ci]
---
.../GFramework.Core.Tests.csproj | 1 +
.../CommandCoroutineExtensionsTests.cs | 429 ++++++++++++++++++
.../QueryCoroutineExtensionsTests.cs | 356 +++++++++++++++
.../coroutine/WaitForEventTests.cs | 270 +++++++++++
.../coroutine/WaitForEventWithTimeoutTests.cs | 328 +++++++++++++
.../events/EventListenerScopeTests.cs | 321 +++++++++++++
6 files changed, 1705 insertions(+)
create mode 100644 GFramework.Core.Tests/coroutine/CommandCoroutineExtensionsTests.cs
create mode 100644 GFramework.Core.Tests/coroutine/QueryCoroutineExtensionsTests.cs
create mode 100644 GFramework.Core.Tests/coroutine/WaitForEventTests.cs
create mode 100644 GFramework.Core.Tests/coroutine/WaitForEventWithTimeoutTests.cs
create mode 100644 GFramework.Core.Tests/events/EventListenerScopeTests.cs
diff --git a/GFramework.Core.Tests/GFramework.Core.Tests.csproj b/GFramework.Core.Tests/GFramework.Core.Tests.csproj
index 86171dc..af6aebe 100644
--- a/GFramework.Core.Tests/GFramework.Core.Tests.csproj
+++ b/GFramework.Core.Tests/GFramework.Core.Tests.csproj
@@ -7,6 +7,7 @@
+
diff --git a/GFramework.Core.Tests/coroutine/CommandCoroutineExtensionsTests.cs b/GFramework.Core.Tests/coroutine/CommandCoroutineExtensionsTests.cs
new file mode 100644
index 0000000..408b83a
--- /dev/null
+++ b/GFramework.Core.Tests/coroutine/CommandCoroutineExtensionsTests.cs
@@ -0,0 +1,429 @@
+using GFramework.Core.Abstractions.architecture;
+using GFramework.Core.Abstractions.command;
+using GFramework.Core.Abstractions.coroutine;
+using GFramework.Core.Abstractions.events;
+using GFramework.Core.Abstractions.rule;
+using GFramework.Core.coroutine.extensions;
+using GFramework.Core.coroutine.instructions;
+using Moq;
+using NUnit.Framework;
+
+namespace GFramework.Core.Tests.coroutine;
+
+///
+/// CommandCoroutineExtensions的单元测试类
+/// 测试内容包括:
+/// - SendCommandCoroutineWithErrorHandler扩展方法
+/// - SendCommandAndWaitEventCoroutine扩展方法
+///
+[TestFixture]
+public class CommandCoroutineExtensionsTests
+{
+ ///
+ /// 测试用的简单命令类
+ ///
+ private class TestCommand : IAsyncCommand
+ {
+ private IArchitectureContext? _context;
+ public void SetContext(IArchitectureContext context) => _context = context;
+ public IArchitectureContext GetContext() => _context!;
+
+ public Task ExecuteAsync()
+ {
+ return Task.CompletedTask;
+ }
+ }
+
+ ///
+ /// 测试用的简单事件类
+ ///
+ private class TestEvent
+ {
+ public string Data { get; set; } = string.Empty;
+ }
+
+ ///
+ /// 上下文感知基类的模拟实现
+ ///
+ private class TestContextAware : IContextAware
+ {
+ public Mock _mockContext = new();
+
+ public IArchitectureContext GetContext()
+ {
+ return _mockContext.Object;
+ }
+
+ public void SetContext(IArchitectureContext context)
+ {
+ }
+ }
+
+ ///
+ /// 验证SendCommandCoroutineWithErrorHandler应该能正常执行成功的命令
+ ///
+ [Test]
+ public async Task SendCommandCoroutineWithErrorHandler_Should_Execute_Successful_Command()
+ {
+ var command = new TestCommand();
+ Exception? capturedException = null;
+ var contextAware = new TestContextAware();
+
+ // 设置上下文发送命令的模拟行为
+ contextAware._mockContext
+ .Setup(ctx => ctx.SendCommandAsync(It.IsAny()))
+ .Returns(Task.CompletedTask);
+
+ var coroutine = contextAware.SendCommandCoroutineWithErrorHandler(command, ex => capturedException = ex);
+
+ // 迭代协程直到完成
+ while (coroutine.MoveNext())
+ {
+ if (coroutine.Current is WaitForTask)
+ {
+ // 等待任务完成
+ await Task.Delay(10);
+ }
+ }
+
+ Assert.That(capturedException, Is.Null);
+ }
+
+ ///
+ /// 验证SendCommandCoroutineWithErrorHandler应该捕获命令执行中的异常
+ ///
+ [Test]
+ public async Task SendCommandCoroutineWithErrorHandler_Should_Capture_Command_Exception()
+ {
+ var command = new TestCommand();
+ Exception? capturedException = null;
+ var contextAware = new TestContextAware();
+ var expectedException = new InvalidOperationException("Test exception");
+
+ // 设置上下文发送命令的模拟行为,返回失败的任务
+ contextAware._mockContext
+ .Setup(ctx => ctx.SendCommandAsync(It.IsAny()))
+ .Returns(Task.FromException(expectedException));
+
+ var coroutine = contextAware.SendCommandCoroutineWithErrorHandler(command, ex => capturedException = ex);
+
+ // 迭代协程直到完成
+ while (coroutine.MoveNext())
+ {
+ if (coroutine.Current is WaitForTask)
+ {
+ // 等待任务完成
+ await Task.Delay(10);
+ }
+ }
+
+ Assert.That(capturedException, Is.Not.Null);
+ // 异常被包装为 AggregateException
+ Assert.That(capturedException, Is.TypeOf());
+ var aggregateException = (AggregateException)capturedException!;
+ Assert.That(aggregateException.InnerException, Is.EqualTo(expectedException));
+ }
+
+ ///
+ /// 验证SendCommandCoroutineWithErrorHandler应该处理null错误回调
+ ///
+ [Test]
+ public async Task SendCommandCoroutineWithErrorHandler_Should_Handle_Null_Error_Handler()
+ {
+ var command = new TestCommand();
+ var contextAware = new TestContextAware();
+ var expectedException = new InvalidOperationException("Test exception");
+
+ // 设置上下文发送命令的模拟行为,返回失败的任务
+ contextAware._mockContext
+ .Setup(ctx => ctx.SendCommandAsync(It.IsAny()))
+ .Returns(Task.FromException(expectedException));
+
+ // 使用null作为错误处理程序
+ var coroutine = contextAware.SendCommandCoroutineWithErrorHandler(command, null);
+
+ // 迭代协程直到完成
+ while (coroutine.MoveNext())
+ {
+ if (coroutine.Current is WaitForTask)
+ {
+ // 等待任务完成
+ await Task.Delay(10);
+ }
+ }
+
+ // 应该不会抛出异常
+ Assert.Pass();
+ }
+
+ ///
+ /// 验证SendCommandAndWaitEventCoroutine应该在事件触发后完成
+ ///
+ [Test]
+ public async Task SendCommandAndWaitEventCoroutine_Should_Complete_After_Event_Triggered()
+ {
+ var command = new TestCommand();
+ var contextAware = new TestContextAware();
+ TestEvent? receivedEvent = null;
+ var eventTriggered = false;
+
+ // 创建事件总线模拟
+ var eventBusMock = new Mock();
+ var unRegisterMock = new Mock();
+
+ Action? eventCallback = null;
+ eventBusMock.Setup(bus => bus.Register(It.IsAny>()))
+ .Returns(unRegisterMock.Object)
+ .Callback>(callback => eventCallback = callback);
+
+ // 设置上下文服务以返回事件总线
+ contextAware._mockContext
+ .Setup(ctx => ctx.GetService())
+ .Returns(eventBusMock.Object);
+
+ // 设置命令执行返回完成的任务
+ contextAware._mockContext
+ .Setup(ctx => ctx.SendCommandAsync(It.IsAny()))
+ .Returns(Task.CompletedTask);
+
+ var coroutine = contextAware.SendCommandAndWaitEventCoroutine(
+ command,
+ ev =>
+ {
+ receivedEvent = ev;
+ eventTriggered = true;
+ });
+
+ // 启动协程并等待命令执行完成
+ coroutine.MoveNext(); // 进入命令发送阶段
+ if (coroutine.Current is WaitForTask)
+ {
+ await Task.Delay(10); // 等待命令任务完成
+ }
+
+ // 此时协程应该在等待事件
+ Assert.That(coroutine.MoveNext(), Is.True); // 等待事件阶段
+
+ // 触发事件
+ var testEvent = new TestEvent { Data = "TestData" };
+ eventCallback?.Invoke(testEvent);
+
+ // 现在协程应该完成
+ Assert.That(coroutine.MoveNext(), Is.False);
+
+ Assert.That(eventTriggered, Is.True);
+ Assert.That(receivedEvent, Is.Not.Null);
+ Assert.That(receivedEvent?.Data, Is.EqualTo("TestData"));
+ }
+
+ ///
+ /// 验证SendCommandAndWaitEventCoroutine应该处理超时情况
+ ///
+ [Test]
+ public void SendCommandAndWaitEventCoroutine_Should_Throw_Timeout_Exception()
+ {
+ var command = new TestCommand();
+ var contextAware = new TestContextAware();
+
+ // 创建事件总线模拟
+ var eventBusMock = new Mock();
+ var unRegisterMock = new Mock();
+
+ eventBusMock.Setup(bus => bus.Register(It.IsAny>()))
+ .Returns(unRegisterMock.Object);
+
+ // 设置上下文服务以返回事件总线
+ contextAware._mockContext
+ .Setup(ctx => ctx.GetService())
+ .Returns(eventBusMock.Object);
+
+ // 设置命令执行返回完成的任务
+ contextAware._mockContext
+ .Setup(ctx => ctx.SendCommandAsync(It.IsAny()))
+ .Returns(Task.CompletedTask);
+
+ // 对于超时情况,我们期望抛出TimeoutException
+ Assert.Throws(() =>
+ {
+ var coroutine = contextAware.SendCommandAndWaitEventCoroutine(
+ command,
+ null,
+ 0.1f); // 0.1秒超时
+
+ // 运行协程直到完成
+ while (coroutine.MoveNext())
+ {
+ if (coroutine.Current is WaitForEventWithTimeout timeoutWait)
+ {
+ // 模拟超时
+ timeoutWait.Update(0.2); // 更新时间超过超时限制
+ }
+ }
+ });
+ }
+
+ ///
+ /// 验证SendCommandAndWaitEventCoroutine应该处理null事件回调
+ ///
+ [Test]
+ public async Task SendCommandAndWaitEventCoroutine_Should_Handle_Null_Event_Callback()
+ {
+ var command = new TestCommand();
+ var contextAware = new TestContextAware();
+
+ // 创建事件总线模拟
+ var eventBusMock = new Mock();
+ var unRegisterMock = new Mock();
+
+ Action? eventCallback = null;
+ eventBusMock.Setup(bus => bus.Register(It.IsAny>()))
+ .Returns(unRegisterMock.Object)
+ .Callback>(callback => eventCallback = callback);
+
+ // 设置上下文服务以返回事件总线
+ contextAware._mockContext
+ .Setup(ctx => ctx.GetService())
+ .Returns(eventBusMock.Object);
+
+ // 设置命令执行返回完成的任务
+ contextAware._mockContext
+ .Setup(ctx => ctx.SendCommandAsync(It.IsAny()))
+ .Returns(Task.CompletedTask);
+
+ // 使用null作为事件回调
+ var coroutine = contextAware.SendCommandAndWaitEventCoroutine(
+ command,
+ null); // null回调
+
+ // 启动协程
+ coroutine.MoveNext(); // 进入命令发送阶段
+ if (coroutine.Current is WaitForTask)
+ {
+ await Task.Delay(10); // 等待命令任务完成
+ }
+
+ // 触发事件
+ var testEvent = new TestEvent { Data = "TestData" };
+ eventCallback?.Invoke(testEvent);
+
+ // 协程应该能正常完成
+ Assert.That(() => coroutine.MoveNext(), Throws.Nothing);
+ }
+
+ ///
+ /// 验证SendCommandAndWaitEventCoroutine应该处理命令执行异常
+ ///
+ [Test]
+ public async Task SendCommandAndWaitEventCoroutine_Should_Handle_Command_Exception()
+ {
+ var command = new TestCommand();
+ var contextAware = new TestContextAware();
+ var expectedException = new InvalidOperationException("Command execution failed");
+
+ // 创建事件总线模拟
+ var eventBusMock = new Mock();
+ var unRegisterMock = new Mock();
+
+ eventBusMock.Setup(bus => bus.Register(It.IsAny>()))
+ .Returns(unRegisterMock.Object);
+
+ // 设置上下文服务以返回事件总线
+ contextAware._mockContext
+ .Setup(ctx => ctx.GetService())
+ .Returns(eventBusMock.Object);
+
+ // 设置命令执行返回失败的任务
+ contextAware._mockContext
+ .Setup(ctx => ctx.SendCommandAsync(It.IsAny()))
+ .Returns(Task.FromException(expectedException));
+
+ var coroutine = contextAware.SendCommandAndWaitEventCoroutine(
+ command,
+ _ => { });
+
+ // 启动协程 - 命令失败时协程仍然继续
+ coroutine.MoveNext(); // 进入命令发送阶段
+ if (coroutine.Current is WaitForTask)
+ {
+ await Task.Delay(10); // 等待命令任务完成
+ }
+
+ // 命令执行失败后,协程继续执行
+ Assert.Pass();
+ }
+
+ ///
+ /// 验证SendCommandCoroutineWithErrorHandler应该返回IEnumerator
+ ///
+ [Test]
+ public void SendCommandCoroutineWithErrorHandler_Should_Return_IEnumerator_Of_YieldInstruction()
+ {
+ var command = new TestCommand();
+ var contextAware = new TestContextAware();
+
+ // 设置上下文发送命令的模拟行为
+ contextAware._mockContext
+ .Setup(ctx => ctx.SendCommandAsync(It.IsAny()))
+ .Returns(Task.CompletedTask);
+
+ var coroutine = contextAware.SendCommandCoroutineWithErrorHandler(command, ex => { });
+
+ Assert.That(coroutine, Is.InstanceOf>());
+ }
+
+ ///
+ /// 验证SendCommandAndWaitEventCoroutine应该返回IEnumerator
+ ///
+ [Test]
+ public void SendCommandAndWaitEventCoroutine_Should_Return_IEnumerator_Of_YieldInstruction()
+ {
+ var command = new TestCommand();
+ var contextAware = new TestContextAware();
+
+ // 创建事件总线模拟
+ var eventBusMock = new Mock();
+ var unRegisterMock = new Mock();
+
+ eventBusMock.Setup(bus => bus.Register(It.IsAny>()))
+ .Returns(unRegisterMock.Object);
+
+ // 设置上下文服务以返回事件总线
+ contextAware._mockContext
+ .Setup(ctx => ctx.GetService())
+ .Returns(eventBusMock.Object);
+
+ // 设置命令执行返回完成的任务
+ contextAware._mockContext
+ .Setup(ctx => ctx.SendCommandAsync(It.IsAny()))
+ .Returns(Task.CompletedTask);
+
+ var coroutine = contextAware.SendCommandAndWaitEventCoroutine(
+ command,
+ ev => { });
+
+ Assert.That(coroutine, Is.InstanceOf>());
+ }
+
+ ///
+ /// 验证SendCommandAndWaitEventCoroutine应该在事件总线为null时处理异常
+ ///
+ [Test]
+ public void SendCommandAndWaitEventCoroutine_Should_Handle_Null_EventBus()
+ {
+ var command = new TestCommand();
+ var contextAware = new TestContextAware();
+
+ // 设置上下文服务以返回null事件总线
+ contextAware._mockContext
+ .Setup(ctx => ctx.GetService())
+ .Returns((IEventBus?)null);
+
+ // 创建协程
+ var coroutine = contextAware.SendCommandAndWaitEventCoroutine(
+ command,
+ ev => { });
+
+ // 调用 MoveNext 时应该抛出异常,因为事件总线为null
+ Assert.Throws(() => coroutine.MoveNext());
+ }
+}
\ No newline at end of file
diff --git a/GFramework.Core.Tests/coroutine/QueryCoroutineExtensionsTests.cs b/GFramework.Core.Tests/coroutine/QueryCoroutineExtensionsTests.cs
new file mode 100644
index 0000000..422d175
--- /dev/null
+++ b/GFramework.Core.Tests/coroutine/QueryCoroutineExtensionsTests.cs
@@ -0,0 +1,356 @@
+using GFramework.Core.Abstractions.architecture;
+using GFramework.Core.Abstractions.coroutine;
+using GFramework.Core.Abstractions.query;
+using GFramework.Core.Abstractions.rule;
+using GFramework.Core.coroutine.extensions;
+using Moq;
+using NUnit.Framework;
+
+namespace GFramework.Core.Tests.coroutine;
+
+///
+/// QueryCoroutineExtensions的单元测试类
+/// 测试内容包括:
+/// - SendQueryCoroutine扩展方法
+///
+[TestFixture]
+public class QueryCoroutineExtensionsTests
+{
+ ///
+ /// 测试用的简单查询类
+ ///
+ private class TestQuery : IQuery
+ {
+ private IArchitectureContext? _context;
+ public string QueryData { get; set; } = string.Empty;
+ public void SetContext(IArchitectureContext context) => _context = context;
+ public IArchitectureContext GetContext() => _context!;
+ public string Do() => QueryData;
+ }
+
+ ///
+ /// 上下文感知基类的模拟实现
+ ///
+ private class TestContextAware : IContextAware
+ {
+ public Mock _mockContext = new Mock();
+
+ public IArchitectureContext GetContext()
+ {
+ return _mockContext.Object;
+ }
+
+ public void SetContext(IArchitectureContext context)
+ {
+ }
+ }
+
+ ///
+ /// 验证SendQueryCoroutine应该能正常执行查询并返回结果
+ ///
+ [Test]
+ public void SendQueryCoroutine_Should_Execute_Query_And_Return_Result()
+ {
+ var query = new TestQuery { QueryData = "TestQueryData" };
+ string? receivedResult = null;
+ var resultReceived = false;
+ var contextAware = new TestContextAware();
+
+ // 设置上下文发送查询的模拟行为
+ contextAware._mockContext
+ .Setup(ctx => ctx.SendQuery(It.IsAny()))
+ .Returns("TestResult");
+
+ var coroutine = contextAware.SendQueryCoroutine(query, result =>
+ {
+ receivedResult = result;
+ resultReceived = true;
+ });
+
+ // 迭代协程直到完成
+ var moved = coroutine.MoveNext();
+
+ // SendQueryCoroutine立即执行并返回,所以MoveNext应该返回false
+ Assert.That(moved, Is.False);
+ Assert.That(resultReceived, Is.True);
+ Assert.That(receivedResult, Is.EqualTo("TestResult"));
+ }
+
+ ///
+ /// 验证SendQueryCoroutine应该处理不同类型的查询和结果
+ ///
+ [Test]
+ public void SendQueryCoroutine_Should_Handle_Different_Query_And_Result_Types()
+ {
+ // 使用整数查询和布尔结果
+ var query = new IntQuery { Value = 42 };
+ bool? receivedResult = null;
+ var resultReceived = false;
+ var contextAware = new TestContextAware();
+
+ // 设置上下文发送查询的模拟行为
+ contextAware._mockContext
+ .Setup(ctx => ctx.SendQuery(It.IsAny()))
+ .Returns(true);
+
+ var coroutine = contextAware.SendQueryCoroutine(query, result =>
+ {
+ receivedResult = result;
+ resultReceived = true;
+ });
+
+ // 迭代协程直到完成
+ var moved = coroutine.MoveNext();
+
+ Assert.That(moved, Is.False);
+ Assert.That(resultReceived, Is.True);
+ Assert.That(receivedResult, Is.True);
+ }
+
+ ///
+ /// 验证SendQueryCoroutine在null回调时应该抛出异常
+ ///
+ [Test]
+ public void SendQueryCoroutine_Should_Throw_When_Null_Result_Callback()
+ {
+ var query = new TestQuery { QueryData = "TestQueryData" };
+ var contextAware = new TestContextAware();
+
+ // 设置上下文发送查询的模拟行为
+ contextAware._mockContext
+ .Setup(ctx => ctx.SendQuery(It.IsAny()))
+ .Returns("TestResult");
+
+ // 使用null作为结果回调,应该抛出NullReferenceException
+ var coroutine = contextAware.SendQueryCoroutine(query, null!);
+
+ // 迭代协程时应该抛出异常
+ Assert.That(() => coroutine.MoveNext(), Throws.TypeOf());
+ }
+
+ ///
+ /// 验证SendQueryCoroutine应该在查询执行期间调用结果处理回调
+ ///
+ [Test]
+ public void SendQueryCoroutine_Should_Call_Result_Callback_During_Execution()
+ {
+ var query = new TestQuery { QueryData = "TestQueryData" };
+ string? receivedResult = null;
+ var callCount = 0;
+ var contextAware = new TestContextAware();
+
+ // 设置上下文发送查询的模拟行为
+ contextAware._mockContext
+ .Setup(ctx => ctx.SendQuery(It.IsAny()))
+ .Returns("ProcessedResult");
+
+ var coroutine = contextAware.SendQueryCoroutine(query, result =>
+ {
+ receivedResult = result;
+ callCount++;
+ });
+
+ // 协程应立即执行查询并调用回调
+ coroutine.MoveNext();
+
+ Assert.That(callCount, Is.EqualTo(1));
+ Assert.That(receivedResult, Is.EqualTo("ProcessedResult"));
+ }
+
+ ///
+ /// 验证SendQueryCoroutine应该返回IEnumerator
+ ///
+ [Test]
+ public void SendQueryCoroutine_Should_Return_IEnumerator_Of_YieldInstruction()
+ {
+ var query = new TestQuery { QueryData = "TestQueryData" };
+ var contextAware = new TestContextAware();
+
+ // 设置上下文发送查询的模拟行为
+ contextAware._mockContext
+ .Setup(ctx => ctx.SendQuery(It.IsAny()))
+ .Returns("TestResult");
+
+ var coroutine = contextAware.SendQueryCoroutine(query, result => { });
+
+ Assert.That(coroutine, Is.InstanceOf>());
+ }
+
+ ///
+ /// 验证SendQueryCoroutine应该在查询抛出异常时处理异常
+ ///
+ [Test]
+ public void SendQueryCoroutine_Should_Handle_Query_Exception()
+ {
+ var query = new TestQuery { QueryData = "TestQueryData" };
+ string? receivedResult = null;
+ var contextAware = new TestContextAware();
+ var expectedException = new InvalidOperationException("Query execution failed");
+
+ // 设置上下文发送查询的模拟行为,让它抛出异常
+ contextAware._mockContext
+ .Setup(ctx => ctx.SendQuery(It.IsAny()))
+ .Throws(expectedException);
+
+ // 由于SendQueryCoroutine会直接执行查询,这可能导致异常
+ Assert.Throws(() =>
+ {
+ var coroutine =
+ contextAware.SendQueryCoroutine(query, result => { receivedResult = result; });
+
+ // 尝试移动协程,这应该会执行查询并抛出异常
+ coroutine.MoveNext();
+ });
+ }
+
+ ///
+ /// 验证SendQueryCoroutine应该正确传递查询参数
+ ///
+ [Test]
+ public void SendQueryCoroutine_Should_Pass_Query_Parameters_Correctly()
+ {
+ var query = new TestQuery { QueryData = "PassedQueryData" };
+ string? receivedResult = null;
+ var contextAware = new TestContextAware();
+ TestQuery? capturedQuery = null;
+
+ // 设置上下文发送查询的模拟行为,并捕获传入的查询参数
+ contextAware._mockContext
+ .Setup(ctx => ctx.SendQuery(It.IsAny()))
+ .Returns((IQuery q) =>
+ {
+ capturedQuery = (TestQuery)q;
+ return $"Processed_{capturedQuery.QueryData}";
+ });
+
+ var coroutine =
+ contextAware.SendQueryCoroutine(query, result => { receivedResult = result; });
+
+ coroutine.MoveNext();
+
+ Assert.That(capturedQuery, Is.Not.Null);
+ Assert.That(capturedQuery!.QueryData, Is.EqualTo("PassedQueryData"));
+ Assert.That(receivedResult, Is.EqualTo("Processed_PassedQueryData"));
+ }
+
+ ///
+ /// 验证SendQueryCoroutine应该处理复杂对象查询
+ ///
+ [Test]
+ public void SendQueryCoroutine_Should_Handle_Complex_Object_Query()
+ {
+ var query = new ComplexQuery
+ {
+ Name = "ComplexName",
+ Values = new List { 1, 2, 3 },
+ Metadata = new Dictionary { { "key", "value" } }
+ };
+
+ ComplexResult? receivedResult = null;
+ var contextAware = new TestContextAware();
+
+ var expectedResult = new ComplexResult
+ {
+ ProcessedName = "Processed_ComplexName",
+ Sum = 6,
+ Count = 3
+ };
+
+ // 设置上下文发送查询的模拟行为
+ contextAware._mockContext
+ .Setup(ctx => ctx.SendQuery(It.IsAny()))
+ .Returns(expectedResult);
+
+ var coroutine =
+ contextAware.SendQueryCoroutine(query, result => { receivedResult = result; });
+
+ coroutine.MoveNext();
+
+ Assert.That(receivedResult, Is.Not.Null);
+ Assert.That(receivedResult!.ProcessedName, Is.EqualTo("Processed_ComplexName"));
+ Assert.That(receivedResult.Sum, Is.EqualTo(6));
+ Assert.That(receivedResult.Count, Is.EqualTo(3));
+ }
+
+ ///
+ /// 验证SendQueryCoroutine应该处理空字符串结果
+ ///
+ [Test]
+ public void SendQueryCoroutine_Should_Handle_Empty_String_Result()
+ {
+ var query = new TestQuery { QueryData = "TestQueryData" };
+ string? receivedResult = null;
+ var contextAware = new TestContextAware();
+
+ // 设置上下文发送查询的模拟行为,返回空字符串
+ contextAware._mockContext
+ .Setup(ctx => ctx.SendQuery(It.IsAny()))
+ .Returns(string.Empty);
+
+ var coroutine =
+ contextAware.SendQueryCoroutine(query, result => { receivedResult = result; });
+
+ coroutine.MoveNext();
+
+ Assert.That(receivedResult, Is.EqualTo(string.Empty));
+ }
+
+ ///
+ /// 验证SendQueryCoroutine应该处理null结果
+ ///
+ [Test]
+ public void SendQueryCoroutine_Should_Handle_Null_Result()
+ {
+ var query = new TestQuery { QueryData = "TestQueryData" };
+ string? receivedResult = "initial";
+ var contextAware = new TestContextAware();
+
+ // 设置上下文发送查询的模拟行为,返回null
+ contextAware._mockContext
+ .Setup(ctx => ctx.SendQuery(It.IsAny()))
+ .Returns((string)null!);
+
+ var coroutine =
+ contextAware.SendQueryCoroutine(query, result => { receivedResult = result; });
+
+ coroutine.MoveNext();
+
+ Assert.That(receivedResult, Is.Null);
+ }
+}
+
+///
+/// 用于测试的整数查询类
+///
+internal class IntQuery : IQuery
+{
+ private IArchitectureContext? _context;
+ public int Value { get; set; }
+ public void SetContext(IArchitectureContext context) => _context = context;
+ public IArchitectureContext GetContext() => _context!;
+ public bool Do() => Value > 0;
+}
+
+///
+/// 用于测试的复杂查询类
+///
+internal class ComplexQuery : IQuery
+{
+ private IArchitectureContext? _context;
+ public string Name { get; set; } = string.Empty;
+ public List Values { get; set; } = new List();
+ public Dictionary Metadata { get; set; } = new Dictionary();
+ public void SetContext(IArchitectureContext context) => _context = context;
+ public IArchitectureContext GetContext() => _context!;
+ public ComplexResult Do() => new ComplexResult { ProcessedName = Name, Sum = Values.Sum(), Count = Values.Count };
+}
+
+///
+/// 用于测试的复杂结果类
+///
+internal class ComplexResult
+{
+ public string ProcessedName { get; set; } = string.Empty;
+ public int Sum { get; set; }
+ public int Count { get; set; }
+}
\ No newline at end of file
diff --git a/GFramework.Core.Tests/coroutine/WaitForEventTests.cs b/GFramework.Core.Tests/coroutine/WaitForEventTests.cs
new file mode 100644
index 0000000..723aa4e
--- /dev/null
+++ b/GFramework.Core.Tests/coroutine/WaitForEventTests.cs
@@ -0,0 +1,270 @@
+using GFramework.Core.Abstractions.coroutine;
+using GFramework.Core.Abstractions.events;
+using GFramework.Core.coroutine.instructions;
+using Moq;
+using NUnit.Framework;
+
+namespace GFramework.Core.Tests.coroutine;
+
+///
+/// WaitForEvent的单元测试类
+/// 测试内容包括:
+/// - 初始化和基本功能
+/// - 事件触发处理
+/// - 资源释放
+/// - 异常处理
+///
+[TestFixture]
+public class WaitForEventTests
+{
+ ///
+ /// 测试用的简单事件类
+ ///
+ private class TestEvent
+ {
+ public string Data { get; set; } = string.Empty;
+ }
+
+ ///
+ /// 验证WaitForEvent初始状态为未完成
+ ///
+ [Test]
+ public void WaitForEvent_Should_Not_Be_Done_Initially()
+ {
+ var eventBusMock = new Mock();
+ var unRegisterMock = new Mock();
+ eventBusMock.Setup(x => x.Register(It.IsAny>()))
+ .Returns(unRegisterMock.Object);
+
+ var wait = new WaitForEvent(eventBusMock.Object);
+
+ Assert.That(wait.IsDone, Is.False);
+ }
+
+ ///
+ /// 验证WaitForEvent应该在事件触发后完成
+ ///
+ [Test]
+ public void WaitForEvent_Should_Be_Done_After_Event_Triggered()
+ {
+ Action? registeredAction = null;
+ var eventBusMock = new Mock();
+ var unRegisterMock = new Mock();
+
+ eventBusMock.Setup(x => x.Register(It.IsAny>()))
+ .Returns(unRegisterMock.Object)
+ .Callback>(action => registeredAction = action);
+
+ var wait = new WaitForEvent(eventBusMock.Object);
+
+ Assert.That(wait.IsDone, Is.False);
+
+ // 触发事件
+ var testEvent = new TestEvent { Data = "TestData" };
+ registeredAction?.Invoke(testEvent);
+
+ Assert.That(wait.IsDone, Is.True);
+ }
+
+ ///
+ /// 验证WaitForEvent应该保存事件数据
+ ///
+ [Test]
+ public void WaitForEvent_Should_Save_Event_Data()
+ {
+ Action? registeredAction = null;
+ var eventBusMock = new Mock();
+ var unRegisterMock = new Mock();
+
+ eventBusMock.Setup(x => x.Register(It.IsAny>()))
+ .Returns(unRegisterMock.Object)
+ .Callback>(action => registeredAction = action);
+
+ var wait = new WaitForEvent(eventBusMock.Object);
+
+ var testEvent = new TestEvent { Data = "TestData" };
+ registeredAction?.Invoke(testEvent);
+
+ Assert.That(wait.EventData, Is.Not.Null);
+ Assert.That(wait.EventData?.Data, Is.EqualTo("TestData"));
+ }
+
+ ///
+ /// 验证WaitForEvent应该在事件触发后保持完成状态
+ ///
+ [Test]
+ public void WaitForEvent_Should_Remain_Done_After_Event_Triggered()
+ {
+ Action? registeredAction = null;
+ var eventBusMock = new Mock();
+ var unRegisterMock = new Mock();
+
+ eventBusMock.Setup(x => x.Register(It.IsAny>()))
+ .Returns(unRegisterMock.Object)
+ .Callback>(action => registeredAction = action);
+
+ var wait = new WaitForEvent(eventBusMock.Object);
+
+ var testEvent = new TestEvent { Data = "TestData" };
+ registeredAction?.Invoke(testEvent);
+
+ Assert.That(wait.IsDone, Is.True);
+
+ // 再次触发事件,确认状态不变
+ registeredAction?.Invoke(new TestEvent { Data = "AnotherData" });
+
+ Assert.That(wait.IsDone, Is.True);
+ }
+
+ ///
+ /// 验证WaitForEvent应该在Dispose后释放资源
+ ///
+ [Test]
+ public void WaitForEvent_Should_Release_Resources_On_Dispose()
+ {
+ var eventBusMock = new Mock();
+ var unRegisterMock = new Mock();
+
+ eventBusMock.Setup(x => x.Register(It.IsAny>()))
+ .Returns(unRegisterMock.Object);
+
+ var wait = new WaitForEvent(eventBusMock.Object);
+
+ wait.Dispose();
+
+ unRegisterMock.Verify(x => x.UnRegister(), Times.Once);
+ }
+
+ ///
+ /// 验证WaitForEvent应该处理多次Dispose调用
+ ///
+ [Test]
+ public void WaitForEvent_Should_Handle_Multiple_Dispose_Calls()
+ {
+ var eventBusMock = new Mock();
+ var unRegisterMock = new Mock();
+
+ eventBusMock.Setup(x => x.Register(It.IsAny>()))
+ .Returns(unRegisterMock.Object);
+
+ var wait = new WaitForEvent(eventBusMock.Object);
+
+ wait.Dispose();
+ // 第二次调用不应引发异常
+ Assert.DoesNotThrow(() => wait.Dispose());
+ }
+
+ ///
+ /// 验证WaitForEvent应该抛出ArgumentNullException当eventBus为null
+ ///
+ [Test]
+ public void WaitForEvent_Should_Throw_ArgumentNullException_When_EventBus_Is_Null()
+ {
+ Assert.Throws(() => new WaitForEvent(null!));
+ }
+
+ ///
+ /// 验证WaitForEvent的Update方法不影响状态
+ ///
+ [Test]
+ public void WaitForEvent_Update_Should_Not_Affect_State()
+ {
+ Action? registeredAction = null;
+ var eventBusMock = new Mock();
+ var unRegisterMock = new Mock();
+
+ eventBusMock.Setup(x => x.Register(It.IsAny>()))
+ .Returns(unRegisterMock.Object)
+ .Callback>(action => registeredAction = action);
+
+ var wait = new WaitForEvent(eventBusMock.Object);
+
+ wait.Update(0.1);
+ Assert.That(wait.IsDone, Is.False);
+
+ var testEvent = new TestEvent { Data = "TestData" };
+ registeredAction?.Invoke(testEvent);
+
+ wait.Update(0.1);
+ Assert.That(wait.IsDone, Is.True);
+ }
+
+ ///
+ /// 验证WaitForEvent实现IYieldInstruction接口
+ ///
+ [Test]
+ public void WaitForEvent_Should_Implement_IYieldInstruction()
+ {
+ var eventBusMock = new Mock();
+ var unRegisterMock = new Mock();
+ eventBusMock.Setup(x => x.Register(It.IsAny>()))
+ .Returns(unRegisterMock.Object);
+
+ var wait = new WaitForEvent(eventBusMock.Object);
+
+ Assert.That(wait, Is.InstanceOf());
+ }
+
+ ///
+ /// 验证WaitForEvent在事件触发后自动注销监听器
+ ///
+ [Test]
+ public void WaitForEvent_Should_Unregister_After_Event_Triggered()
+ {
+ Action? registeredAction = null;
+ var eventBusMock = new Mock();
+ var unRegisterMock = new Mock();
+
+ eventBusMock.Setup(x => x.Register(It.IsAny>()))
+ .Returns(unRegisterMock.Object)
+ .Callback>(action => registeredAction = action);
+
+ var wait = new WaitForEvent(eventBusMock.Object);
+
+ var testEvent = new TestEvent { Data = "TestData" };
+ registeredAction?.Invoke(testEvent);
+
+ // 事件触发后,Update方法应该注销监听器
+ wait.Update(0.1);
+
+ unRegisterMock.Verify(x => x.UnRegister(), Times.AtLeastOnce);
+ }
+
+ ///
+ /// 验证WaitForEventEventData为null当没有事件触发
+ ///
+ [Test]
+ public void WaitForEvent_EventData_Should_Be_Null_When_No_Event_Triggered()
+ {
+ var eventBusMock = new Mock();
+ var unRegisterMock = new Mock();
+ eventBusMock.Setup(x => x.Register(It.IsAny>()))
+ .Returns(unRegisterMock.Object);
+
+ var wait = new WaitForEvent(eventBusMock.Object);
+
+ Assert.That(wait.EventData, Is.Null);
+ }
+
+ ///
+ /// 验证WaitForEventEventData在事件触发后不为null
+ ///
+ [Test]
+ public void WaitForEvent_EventData_Should_Not_Be_Null_After_Event_Triggered()
+ {
+ Action? registeredAction = null;
+ var eventBusMock = new Mock();
+ var unRegisterMock = new Mock();
+
+ eventBusMock.Setup(x => x.Register(It.IsAny>()))
+ .Returns(unRegisterMock.Object)
+ .Callback>(action => registeredAction = action);
+
+ var wait = new WaitForEvent(eventBusMock.Object);
+
+ var testEvent = new TestEvent { Data = "TestData" };
+ registeredAction?.Invoke(testEvent);
+
+ Assert.That(wait.EventData, Is.Not.Null);
+ }
+}
\ No newline at end of file
diff --git a/GFramework.Core.Tests/coroutine/WaitForEventWithTimeoutTests.cs b/GFramework.Core.Tests/coroutine/WaitForEventWithTimeoutTests.cs
new file mode 100644
index 0000000..dc2ee1c
--- /dev/null
+++ b/GFramework.Core.Tests/coroutine/WaitForEventWithTimeoutTests.cs
@@ -0,0 +1,328 @@
+using GFramework.Core.Abstractions.coroutine;
+using GFramework.Core.Abstractions.events;
+using GFramework.Core.coroutine.instructions;
+using Moq;
+using NUnit.Framework;
+
+namespace GFramework.Core.Tests.coroutine;
+
+///
+/// WaitForEventWithTimeout的单元测试类
+/// 测试内容包括:
+/// - 初始化和基本功能
+/// - 超时处理
+/// - 事件提前触发
+/// - 异常处理
+///
+[TestFixture]
+public class WaitForEventWithTimeoutTests
+{
+ ///
+ /// 测试用的简单事件类
+ ///
+ private class TestEvent
+ {
+ public string Data { get; set; } = string.Empty;
+ }
+
+ ///
+ /// 验证WaitForEventWithTimeout初始状态为未完成且未超时
+ ///
+ [Test]
+ public void WaitForEventWithTimeout_Should_Not_Be_Done_Initially()
+ {
+ var eventBusMock = new Mock();
+ var unRegisterMock = new Mock();
+ eventBusMock.Setup(x => x.Register(It.IsAny>()))
+ .Returns(unRegisterMock.Object);
+
+ var waitForEvent = new WaitForEvent(eventBusMock.Object);
+ var wait = new WaitForEventWithTimeout(waitForEvent, 2.0f);
+
+ Assert.That(wait.IsDone, Is.False);
+ Assert.That(wait.IsTimeout, Is.False);
+ }
+
+ ///
+ /// 验证WaitForEventWithTimeout应该在超时时完成
+ ///
+ [Test]
+ public void WaitForEventWithTimeout_Should_Be_Done_When_Timeout()
+ {
+ var eventBusMock = new Mock();
+ var unRegisterMock = new Mock();
+ eventBusMock.Setup(x => x.Register(It.IsAny>()))
+ .Returns(unRegisterMock.Object);
+
+ var waitForEvent = new WaitForEvent(eventBusMock.Object);
+ var wait = new WaitForEventWithTimeout(waitForEvent, 1.0f);
+
+ // 更新时间超过超时时间
+ wait.Update(1.5);
+
+ Assert.That(wait.IsDone, Is.True);
+ Assert.That(wait.IsTimeout, Is.True);
+ }
+
+ ///
+ /// 验证WaitForEventWithTimeout应该在事件触发时完成
+ ///
+ [Test]
+ public void WaitForEventWithTimeout_Should_Be_Done_When_Event_Triggered()
+ {
+ Action? registeredAction = null;
+ var eventBusMock = new Mock();
+ var unRegisterMock = new Mock();
+
+ eventBusMock.Setup(x => x.Register(It.IsAny>()))
+ .Returns(unRegisterMock.Object)
+ .Callback>(action => registeredAction = action);
+
+ var waitForEvent = new WaitForEvent(eventBusMock.Object);
+ var wait = new WaitForEventWithTimeout(waitForEvent, 2.0f);
+
+ // 触发事件
+ var testEvent = new TestEvent { Data = "TestData" };
+ registeredAction?.Invoke(testEvent);
+
+ Assert.That(wait.IsDone, Is.True);
+ Assert.That(wait.IsTimeout, Is.False);
+ }
+
+ ///
+ /// 验证WaitForEventWithTimeout应该在事件触发后保存事件数据
+ ///
+ [Test]
+ public void WaitForEventWithTimeout_Should_Save_Event_Data()
+ {
+ Action? registeredAction = null;
+ var eventBusMock = new Mock();
+ var unRegisterMock = new Mock();
+
+ eventBusMock.Setup(x => x.Register(It.IsAny>()))
+ .Returns(unRegisterMock.Object)
+ .Callback>(action => registeredAction = action);
+
+ var waitForEvent = new WaitForEvent(eventBusMock.Object);
+ var wait = new WaitForEventWithTimeout(waitForEvent, 2.0f);
+
+ var testEvent = new TestEvent { Data = "TestData" };
+ registeredAction?.Invoke(testEvent);
+
+ Assert.That(wait.EventData, Is.Not.Null);
+ Assert.That(wait.EventData?.Data, Is.EqualTo("TestData"));
+ }
+
+ ///
+ /// 验证WaitForEventWithTimeout应该在超时后返回null事件数据
+ ///
+ [Test]
+ public void WaitForEventWithTimeout_Should_Return_Null_EventData_When_Timeout()
+ {
+ var eventBusMock = new Mock();
+ var unRegisterMock = new Mock();
+ eventBusMock.Setup(x => x.Register(It.IsAny>()))
+ .Returns(unRegisterMock.Object);
+
+ var waitForEvent = new WaitForEvent(eventBusMock.Object);
+ var wait = new WaitForEventWithTimeout(waitForEvent, 1.0f);
+
+ wait.Update(1.5);
+
+ Assert.That(wait.EventData, Is.Null);
+ }
+
+ ///
+ /// 验证WaitForEventWithTimeout应该在事件触发前正确计算超时
+ ///
+ [Test]
+ public void WaitForEventWithTimeout_Should_Calculate_Timeout_Correctly()
+ {
+ var eventBusMock = new Mock();
+ var unRegisterMock = new Mock();
+ eventBusMock.Setup(x => x.Register(It.IsAny>()))
+ .Returns(unRegisterMock.Object);
+
+ var waitForEvent = new WaitForEvent(eventBusMock.Object);
+ var wait = new WaitForEventWithTimeout(waitForEvent, 2.0f);
+
+ wait.Update(1.0);
+ Assert.That(wait.IsTimeout, Is.False);
+ Assert.That(wait.IsDone, Is.False);
+
+ wait.Update(0.5);
+ Assert.That(wait.IsTimeout, Is.False);
+ Assert.That(wait.IsDone, Is.False);
+
+ wait.Update(0.6); // 总共2.1秒,超过2.0秒超时时间
+ Assert.That(wait.IsTimeout, Is.True);
+ Assert.That(wait.IsDone, Is.True);
+ }
+
+ ///
+ /// 验证WaitForEventWithTimeout应该在事件触发后忽略后续超时
+ ///
+ [Test]
+ public void WaitForEventWithTimeout_Should_Ignore_Timeout_After_Event_Triggered()
+ {
+ Action? registeredAction = null;
+ var eventBusMock = new Mock();
+ var unRegisterMock = new Mock();
+
+ eventBusMock.Setup(x => x.Register(It.IsAny>()))
+ .Returns(unRegisterMock.Object)
+ .Callback>(action => registeredAction = action);
+
+ var waitForEvent = new WaitForEvent(eventBusMock.Object);
+ var wait = new WaitForEventWithTimeout(waitForEvent, 1.0f);
+
+ // 触发事件
+ var testEvent = new TestEvent { Data = "TestData" };
+ registeredAction?.Invoke(testEvent);
+
+ Assert.That(wait.IsDone, Is.True);
+ Assert.That(wait.IsTimeout, Is.False);
+
+ // 即使时间超过了超时限制,也不应标记为超时
+ wait.Update(2.0);
+ Assert.That(wait.IsDone, Is.True);
+ Assert.That(wait.IsTimeout, Is.False);
+ }
+
+ ///
+ /// 验证WaitForEventWithTimeout应该抛出ArgumentNullException当waitForEvent为null
+ ///
+ [Test]
+ public void WaitForEventWithTimeout_Should_Throw_ArgumentNullException_When_WaitForEvent_Is_Null()
+ {
+ Assert.Throws(() => new WaitForEventWithTimeout(null!, 1.0f));
+ }
+
+ ///
+ /// 验证WaitForEventWithTimeout应该正确处理Update方法
+ ///
+ [Test]
+ public void WaitForEventWithTimeout_Update_Should_Work_Correctly()
+ {
+ Action? registeredAction = null;
+ var eventBusMock = new Mock();
+ var unRegisterMock = new Mock();
+
+ eventBusMock.Setup(x => x.Register(It.IsAny>()))
+ .Returns(unRegisterMock.Object)
+ .Callback>(action => registeredAction = action);
+
+ var waitForEvent = new WaitForEvent(eventBusMock.Object);
+ var wait = new WaitForEventWithTimeout(waitForEvent, 2.0f);
+
+ // 更新时间但未超过超时时间
+ wait.Update(1.0);
+ Assert.That(wait.IsDone, Is.False);
+ Assert.That(wait.IsTimeout, Is.False);
+
+ // 触发事件
+ var testEvent = new TestEvent { Data = "TestData" };
+ registeredAction?.Invoke(testEvent);
+
+ Assert.That(wait.IsDone, Is.True);
+ Assert.That(wait.IsTimeout, Is.False);
+ }
+
+ ///
+ /// 验证WaitForEventWithTimeout实现IYieldInstruction接口
+ ///
+ [Test]
+ public void WaitForEventWithTimeout_Should_Implement_IYieldInstruction()
+ {
+ var eventBusMock = new Mock();
+ var unRegisterMock = new Mock();
+ eventBusMock.Setup(x => x.Register(It.IsAny>()))
+ .Returns(unRegisterMock.Object);
+
+ var waitForEvent = new WaitForEvent(eventBusMock.Object);
+ var wait = new WaitForEventWithTimeout(waitForEvent, 2.0f);
+
+ Assert.That(wait, Is.InstanceOf());
+ }
+
+ ///
+ /// 验证WaitForEventWithTimeout应该处理小超时时间
+ ///
+ [Test]
+ public void WaitForEventWithTimeout_Should_Handle_Small_Timeout()
+ {
+ var eventBusMock = new Mock();
+ var unRegisterMock = new Mock();
+ eventBusMock.Setup(x => x.Register(It.IsAny>()))
+ .Returns(unRegisterMock.Object);
+
+ var waitForEvent = new WaitForEvent(eventBusMock.Object);
+ var wait = new WaitForEventWithTimeout(waitForEvent, 0.1f);
+
+ wait.Update(0.2);
+
+ Assert.That(wait.IsTimeout, Is.True);
+ Assert.That(wait.IsDone, Is.True);
+ }
+
+ ///
+ /// 验证WaitForEventWithTimeout应该处理大超时时间
+ ///
+ [Test]
+ public void WaitForEventWithTimeout_Should_Handle_Large_Timeout()
+ {
+ var eventBusMock = new Mock();
+ var unRegisterMock = new Mock();
+ eventBusMock.Setup(x => x.Register(It.IsAny>()))
+ .Returns(unRegisterMock.Object);
+
+ var waitForEvent = new WaitForEvent(eventBusMock.Object);
+ var wait = new WaitForEventWithTimeout(waitForEvent, 10.0f);
+
+ wait.Update(5.0);
+
+ Assert.That(wait.IsTimeout, Is.False);
+ Assert.That(wait.IsDone, Is.False);
+ }
+
+ ///
+ /// 验证WaitForEventWithTimeout应该在事件触发后忽略后续超时并保持状态
+ ///
+ [Test]
+ public void WaitForEventWithTimeout_Should_Ignore_Timeout_And_Maintain_State_After_Event_Triggered()
+ {
+ Action? registeredAction = null;
+ var eventBusMock = new Mock();
+ var unRegisterMock = new Mock();
+
+ eventBusMock.Setup(x => x.Register(It.IsAny>()))
+ .Returns(unRegisterMock.Object)
+ .Callback>(action => registeredAction = action);
+
+ var waitForEvent = new WaitForEvent(eventBusMock.Object);
+ var wait = new WaitForEventWithTimeout(waitForEvent, 1.0f);
+
+ // 触发事件
+ var testEvent = new TestEvent { Data = "TestData" };
+ registeredAction?.Invoke(testEvent);
+
+ Assert.That(wait.IsDone, Is.True);
+ Assert.That(wait.IsTimeout, Is.False);
+ Assert.That(wait.EventData, Is.Not.Null);
+ Assert.That(wait.EventData?.Data, Is.EqualTo("TestData"));
+
+ // 即使时间超过了超时限制,也不应标记为超时,状态应保持不变
+ wait.Update(2.0);
+ Assert.That(wait.IsDone, Is.True);
+ Assert.That(wait.IsTimeout, Is.False);
+ Assert.That(wait.EventData, Is.Not.Null);
+ Assert.That(wait.EventData?.Data, Is.EqualTo("TestData"));
+
+ // 再次更新,状态仍应保持不变
+ wait.Update(1.0);
+ Assert.That(wait.IsDone, Is.True);
+ Assert.That(wait.IsTimeout, Is.False);
+ Assert.That(wait.EventData, Is.Not.Null);
+ Assert.That(wait.EventData?.Data, Is.EqualTo("TestData"));
+ }
+}
\ No newline at end of file
diff --git a/GFramework.Core.Tests/events/EventListenerScopeTests.cs b/GFramework.Core.Tests/events/EventListenerScopeTests.cs
new file mode 100644
index 0000000..b63e28f
--- /dev/null
+++ b/GFramework.Core.Tests/events/EventListenerScopeTests.cs
@@ -0,0 +1,321 @@
+using GFramework.Core.Abstractions.events;
+using GFramework.Core.events;
+using Moq;
+using NUnit.Framework;
+
+namespace GFramework.Core.Tests.events;
+
+///
+/// EventListenerScope的单元测试类
+/// 测试内容包括:
+/// - 初始化和基本功能
+/// - 事件触发处理
+/// - 资源释放
+/// - 多次触发事件
+///
+[TestFixture]
+public class EventListenerScopeTests
+{
+ ///
+ /// 测试用的简单事件类
+ ///
+ private class TestEvent
+ {
+ public string Data { get; set; } = string.Empty;
+ }
+
+ ///
+ /// 验证EventListenerScope初始状态为未触发
+ ///
+ [Test]
+ public void EventListenerScope_Should_Not_Be_Triggered_Initially()
+ {
+ var eventBusMock = new Mock();
+ var unRegisterMock = new Mock();
+ eventBusMock.Setup(x => x.Register(It.IsAny>()))
+ .Returns(unRegisterMock.Object);
+
+ using var scope = new EventListenerScope(eventBusMock.Object);
+
+ Assert.That(scope.IsTriggered, Is.False);
+ }
+
+ ///