From e83dd278b37be38549c992e25b7cef570fcdedb7 Mon Sep 17 00:00:00 2001 From: GeWuYou <95328647+GeWuYou@users.noreply.github.com> Date: Tue, 10 Feb 2026 23:35:14 +0800 Subject: [PATCH] =?UTF-8?q?test(coroutine):=20=E6=B7=BB=E5=8A=A0=E5=8D=8F?= =?UTF-8?q?=E7=A8=8B=E6=8C=87=E4=BB=A4=E5=8D=95=E5=85=83=E6=B5=8B=E8=AF=95?= =?UTF-8?q?=E5=B9=B6=E6=94=B9=E8=BF=9B=E7=8E=B0=E6=9C=89=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 为 Delay 指令添加完整的单元测试覆盖各种时间情况 - 为 WaitForCoroutine 指令添加单元测试验证协程等待功能 - 为 WaitForFrames 指令添加单元测试覆盖帧计数逻辑 - 为 WaitForTask 指令添加单元测试包括异常处理场景 - 为 WaitOneFrame 指令添加单元测试验证单帧等待 - 为 WaitUntil 和 WaitWhile 指令添加单元测试覆盖谓词逻辑 - 将 WaitForMultipleEventsTests 中的异步方法标记为 async Task 类型 - 修改测试事件类的 Data 属性为可变的 set 访问器而不是只读 init - 优化 WaitForMultipleEventsTests 中的断言注释描述 --- GFramework.Core.Tests/coroutine/DelayTests.cs | 66 +++++++++++++ .../coroutine/WaitForCoroutineTests.cs | 42 ++++++++ .../coroutine/WaitForFramesTests.cs | 74 ++++++++++++++ .../coroutine/WaitForMultipleEventsTests.cs | 25 ++--- .../coroutine/WaitForTaskTTests.cs | 96 +++++++++++++++++++ .../coroutine/WaitOneFrameTests.cs | 46 +++++++++ .../coroutine/WaitUntilTests.cs | 55 +++++++++++ .../coroutine/WaitWhileTests.cs | 66 +++++++++++++ 8 files changed, 454 insertions(+), 16 deletions(-) create mode 100644 GFramework.Core.Tests/coroutine/DelayTests.cs create mode 100644 GFramework.Core.Tests/coroutine/WaitForCoroutineTests.cs create mode 100644 GFramework.Core.Tests/coroutine/WaitForFramesTests.cs create mode 100644 GFramework.Core.Tests/coroutine/WaitForTaskTTests.cs create mode 100644 GFramework.Core.Tests/coroutine/WaitOneFrameTests.cs create mode 100644 GFramework.Core.Tests/coroutine/WaitUntilTests.cs create mode 100644 GFramework.Core.Tests/coroutine/WaitWhileTests.cs diff --git a/GFramework.Core.Tests/coroutine/DelayTests.cs b/GFramework.Core.Tests/coroutine/DelayTests.cs new file mode 100644 index 0000000..e3ff5dd --- /dev/null +++ b/GFramework.Core.Tests/coroutine/DelayTests.cs @@ -0,0 +1,66 @@ +using GFramework.Core.coroutine.instructions; +using NUnit.Framework; + +namespace GFramework.Core.Tests.coroutine +{ + [TestFixture] + public class DelayTests + { + [Test] + public void Constructor_SetsInitialRemainingTime() + { + // Arrange & Act + var delay = new Delay(2.5); + + // Assert + Assert.That(delay.IsDone, Is.False); + } + + [Test] + public void Update_ReducesRemainingTime() + { + // Arrange + var delay = new Delay(2.0); + + // Act + delay.Update(0.5); + + // Assert + Assert.That(delay.IsDone, Is.False); + } + + [Test] + public void Update_MultipleTimes_EventuallyCompletes() + { + // Arrange + var delay = new Delay(1.0); + + // Act + delay.Update(0.5); + delay.Update(0.6); // Total: 1.1 > 1.0, so should be done + + // Assert + Assert.That(delay.IsDone, Is.True); + } + + [Test] + public void NegativeTime_TreatedAsZero() + { + // Arrange & Act + var delay = new Delay(-1.0); + + // Assert + Assert.That(delay.IsDone, Is.True); + } + + [Test] + public void ZeroTime_CompletesImmediately() + { + // Arrange & Act + var delay = new Delay(0.0); + + // Assert + Assert.That(delay.IsDone, Is.True); + } + } +} \ No newline at end of file diff --git a/GFramework.Core.Tests/coroutine/WaitForCoroutineTests.cs b/GFramework.Core.Tests/coroutine/WaitForCoroutineTests.cs new file mode 100644 index 0000000..768072d --- /dev/null +++ b/GFramework.Core.Tests/coroutine/WaitForCoroutineTests.cs @@ -0,0 +1,42 @@ +using GFramework.Core.Abstractions.coroutine; +using GFramework.Core.coroutine.instructions; +using NUnit.Framework; + +namespace GFramework.Core.Tests.coroutine +{ + [TestFixture] + public class WaitForCoroutineTests + { + [Test] + public void Constructor_CreatesInstance() + { + // Arrange + var coroutine = CreateDummyCoroutine(); + + // Act + var waitForCoroutine = new WaitForCoroutine(coroutine); + + // Assert + Assert.That(waitForCoroutine.IsDone, Is.False); + } + + [Test] + public void Update_DoesNotChangeState() + { + // Arrange + var coroutine = CreateDummyCoroutine(); + var waitForCoroutine = new WaitForCoroutine(coroutine); + + // Act + waitForCoroutine.Update(1.0); + + // Assert + Assert.That(waitForCoroutine.IsDone, Is.False); + } + + private static IEnumerator CreateDummyCoroutine() + { + return new List().GetEnumerator(); + } + } +} \ No newline at end of file diff --git a/GFramework.Core.Tests/coroutine/WaitForFramesTests.cs b/GFramework.Core.Tests/coroutine/WaitForFramesTests.cs new file mode 100644 index 0000000..43c2a68 --- /dev/null +++ b/GFramework.Core.Tests/coroutine/WaitForFramesTests.cs @@ -0,0 +1,74 @@ +using GFramework.Core.coroutine.instructions; +using NUnit.Framework; + +namespace GFramework.Core.Tests.coroutine +{ + [TestFixture] + public class WaitForFramesTests + { + [Test] + public void Constructor_SetsInitialFrameCount() + { + // Arrange & Act + var waitForFrames = new WaitForFrames(3); + + // Assert + Assert.That(waitForFrames.IsDone, Is.False); + } + + [Test] + public void Update_ReducesFrameCount() + { + // Arrange + var waitForFrames = new WaitForFrames(2); + + // Act + waitForFrames.Update(0.1); + + // Assert + Assert.That(waitForFrames.IsDone, Is.False); + } + + [Test] + public void MultipleUpdates_EventuallyCompletes() + { + // Arrange + var waitForFrames = new WaitForFrames(2); + + // Act + waitForFrames.Update(0.1); // 2-1 = 1 frame remaining + waitForFrames.Update(0.1); // 1-1 = 0 frames remaining + + // Assert + Assert.That(waitForFrames.IsDone, Is.True); + } + + [Test] + public void NegativeFrameCount_TreatedAsOne() + { + // Arrange & Act + var waitForFrames = new WaitForFrames(-1); + + // Assert + Assert.That(waitForFrames.IsDone, Is.False); + + // One update should complete it + waitForFrames.Update(0.1); + Assert.That(waitForFrames.IsDone, Is.True); + } + + [Test] + public void ZeroFrameCount_TreatedAsOne() + { + // Arrange & Act + var waitForFrames = new WaitForFrames(0); + + // Assert + Assert.That(waitForFrames.IsDone, Is.False); + + // One update should complete it + waitForFrames.Update(0.1); + Assert.That(waitForFrames.IsDone, Is.True); + } + } +} \ No newline at end of file diff --git a/GFramework.Core.Tests/coroutine/WaitForMultipleEventsTests.cs b/GFramework.Core.Tests/coroutine/WaitForMultipleEventsTests.cs index e059db2..8bc3013 100644 --- a/GFramework.Core.Tests/coroutine/WaitForMultipleEventsTests.cs +++ b/GFramework.Core.Tests/coroutine/WaitForMultipleEventsTests.cs @@ -34,7 +34,7 @@ namespace GFramework.Core.Tests.coroutine } [Test] - public Task FirstEventWins_WhenBothEventsFired() + public async Task FirstEventWins_WhenBothEventsFired() { // Arrange var waitForMultipleEvents = new WaitForMultipleEvents(eventBus); @@ -48,11 +48,10 @@ namespace GFramework.Core.Tests.coroutine Assert.That(waitForMultipleEvents.TriggeredBy, Is.EqualTo(1)); // First event should win Assert.That(waitForMultipleEvents.FirstEventData?.Data, Is.EqualTo("first_event")); Assert.That(waitForMultipleEvents.SecondEventData, Is.Null); - return Task.CompletedTask; } [Test] - public Task SecondEventWins_WhenOnlySecondEventFired() + public async Task SecondEventWins_WhenOnlySecondEventFired() { // Arrange var waitForMultipleEvents = new WaitForMultipleEvents(eventBus); @@ -65,11 +64,10 @@ namespace GFramework.Core.Tests.coroutine Assert.That(waitForMultipleEvents.TriggeredBy, Is.EqualTo(2)); // Second event should win Assert.That(waitForMultipleEvents.SecondEventData?.Data, Is.EqualTo("second_event")); Assert.That(waitForMultipleEvents.FirstEventData, Is.Null); - return Task.CompletedTask; } [Test] - public Task FirstEventWins_WhenBothEventsFiredInReverseOrder() + public async Task FirstEventWins_WhenBothEventsFiredInReverseOrder() { // Arrange var waitForMultipleEvents = new WaitForMultipleEvents(eventBus); @@ -80,16 +78,14 @@ namespace GFramework.Core.Tests.coroutine // Assert Assert.That(waitForMultipleEvents.IsDone, Is.True); - // Second event should win because it fired first and set _done = true - Assert.That(waitForMultipleEvents.TriggeredBy, - Is.EqualTo(2)); // Second event actually won since it fired first + // Actually, the second event should win because it fired first and set _done = true + Assert.That(waitForMultipleEvents.TriggeredBy, Is.EqualTo(2)); // Second event wins since it fired first Assert.That(waitForMultipleEvents.SecondEventData?.Data, Is.EqualTo("second_event")); Assert.That(waitForMultipleEvents.FirstEventData, Is.Null); - return Task.CompletedTask; } [Test] - public Task MultipleEvents_AfterCompletion_DoNotOverrideState() + public async Task MultipleEvents_AfterCompletion_DoNotOverrideState() { // Arrange var waitForMultipleEvents = new WaitForMultipleEvents(eventBus); @@ -111,11 +107,10 @@ namespace GFramework.Core.Tests.coroutine Assert.That(waitForMultipleEvents.FirstEventData?.Data, Is.EqualTo("first_event")); // Should remain unchanged Assert.That(waitForMultipleEvents.SecondEventData, Is.Null); // Should remain null - return Task.CompletedTask; } [Test] - public Task Disposal_PreventsFurtherEventHandling() + public async Task Disposal_PreventsFurtherEventHandling() { // Arrange var waitForMultipleEvents = new WaitForMultipleEvents(eventBus); @@ -130,19 +125,17 @@ namespace GFramework.Core.Tests.coroutine // Since we disposed, no event data should be captured Assert.That(waitForMultipleEvents.FirstEventData, Is.Null); Assert.That(waitForMultipleEvents.IsDone, Is.False); // Should remain false after disposal - - return Task.CompletedTask; } // Test event classes private class TestEvent1 { - public string Data { get; init; } = string.Empty; + public string Data { get; set; } = string.Empty; } private class TestEvent2 { - public string Data { get; init; } = string.Empty; + public string Data { get; set; } = string.Empty; } } } \ No newline at end of file diff --git a/GFramework.Core.Tests/coroutine/WaitForTaskTTests.cs b/GFramework.Core.Tests/coroutine/WaitForTaskTTests.cs new file mode 100644 index 0000000..ab446cd --- /dev/null +++ b/GFramework.Core.Tests/coroutine/WaitForTaskTTests.cs @@ -0,0 +1,96 @@ +using GFramework.Core.coroutine.instructions; +using NUnit.Framework; + +namespace GFramework.Core.Tests.coroutine +{ + [TestFixture] + public class WaitForTaskTTests + { + [Test] + public void Constructor_WithNullTask_ThrowsArgumentNullException() + { + // Act & Assert + Assert.Throws(() => new WaitForTask(null!)); + } + + [Test] + public async Task Constructor_WithCompletedTask_IsDoneImmediately() + { + // Arrange + var completedTask = Task.FromResult("test"); + + // Act + var waitForTask = new WaitForTask(completedTask); + + // Assert + Assert.That(waitForTask.IsDone, Is.True); + Assert.That(waitForTask.Result, Is.EqualTo("test")); + } + + [Test] + public async Task Constructor_WithIncompleteTask_IsNotDoneInitially() + { + // Arrange + var tcs = new TaskCompletionSource(); + var incompleteTask = tcs.Task; + + // Act + var waitForTask = new WaitForTask(incompleteTask); + + // Assert + Assert.That(waitForTask.IsDone, Is.False); + } + + [Test] + public async Task TaskCompletes_CallbackSetsDoneFlag() + { + // Arrange + var tcs = new TaskCompletionSource(); + var task = tcs.Task; + var waitForTask = new WaitForTask(task); + + // Assert initial state + Assert.That(waitForTask.IsDone, Is.False); + + // Act + tcs.SetResult("completed"); + await Task.Delay(10); // Allow time for continuation + + // Assert final state + Assert.That(waitForTask.IsDone, Is.True); + Assert.That(waitForTask.Result, Is.EqualTo("completed")); + } + + [Test] + public async Task Update_DoesNotChangeState() + { + // Arrange + var completedTask = Task.FromResult("test"); + var waitForTask = new WaitForTask(completedTask); + + // Act + waitForTask.Update(0.1); + + // Assert + Assert.That(waitForTask.IsDone, Is.True); + } + + [Test] + public async Task TaskWithException_HoldsException() + { + // Arrange + var tcs = new TaskCompletionSource(); + var task = tcs.Task; + var waitForTask = new WaitForTask(task); + + // Act + tcs.SetException(new InvalidOperationException("Test exception")); + await Task.Delay(10); // Allow time for continuation + + // Assert + Assert.That(waitForTask.IsDone, Is.True); + Assert.That(waitForTask.Exception, Is.Not.Null); + Assert.That(waitForTask.Exception?.InnerException, Is.TypeOf()); + } + } +} \ No newline at end of file diff --git a/GFramework.Core.Tests/coroutine/WaitOneFrameTests.cs b/GFramework.Core.Tests/coroutine/WaitOneFrameTests.cs new file mode 100644 index 0000000..1f2af7a --- /dev/null +++ b/GFramework.Core.Tests/coroutine/WaitOneFrameTests.cs @@ -0,0 +1,46 @@ +using GFramework.Core.coroutine.instructions; +using NUnit.Framework; + +namespace GFramework.Core.Tests.coroutine +{ + [TestFixture] + public class WaitOneFrameTests + { + [Test] + public void Constructor_CreatesInstance() + { + // Act + var waitOneFrame = new WaitOneFrame(); + + // Assert + Assert.That(waitOneFrame.IsDone, Is.False); + } + + [Test] + public void Update_MakesItDone() + { + // Arrange + var waitOneFrame = new WaitOneFrame(); + + // Act + waitOneFrame.Update(0.1); + + // Assert + Assert.That(waitOneFrame.IsDone, Is.True); + } + + [Test] + public void Update_MultipleTimes_RemainsDone() + { + // Arrange + var waitOneFrame = new WaitOneFrame(); + + // Act + waitOneFrame.Update(0.1); + waitOneFrame.Update(0.1); + + // Assert + Assert.That(waitOneFrame.IsDone, Is.True); + } + } +} \ No newline at end of file diff --git a/GFramework.Core.Tests/coroutine/WaitUntilTests.cs b/GFramework.Core.Tests/coroutine/WaitUntilTests.cs new file mode 100644 index 0000000..47fffb7 --- /dev/null +++ b/GFramework.Core.Tests/coroutine/WaitUntilTests.cs @@ -0,0 +1,55 @@ +using GFramework.Core.coroutine.instructions; +using NUnit.Framework; + +namespace GFramework.Core.Tests.coroutine +{ + [TestFixture] + public class WaitUntilTests + { + [Test] + public void Constructor_WithNullPredicate_ThrowsArgumentNullException() + { + // Act & Assert + Assert.Throws(() => new WaitUntil(null!)); + } + + [Test] + public void IsDone_ReturnsPredicateResult_True() + { + // Arrange + var condition = false; + var waitUntil = new WaitUntil(() => condition); + + // Act + condition = true; + + // Assert + Assert.That(waitUntil.IsDone, Is.True); + } + + [Test] + public void IsDone_ReturnsPredicateResult_False() + { + // Arrange + var condition = false; + var waitUntil = new WaitUntil(() => condition); + + // Assert + Assert.That(waitUntil.IsDone, Is.False); + } + + [Test] + public void Update_DoesNotChangeState() + { + // Arrange + var condition = false; + var waitUntil = new WaitUntil(() => condition); + + // Act + waitUntil.Update(0.1); + + // Assert + Assert.That(waitUntil.IsDone, Is.False); + } + } +} \ No newline at end of file diff --git a/GFramework.Core.Tests/coroutine/WaitWhileTests.cs b/GFramework.Core.Tests/coroutine/WaitWhileTests.cs new file mode 100644 index 0000000..9829b7e --- /dev/null +++ b/GFramework.Core.Tests/coroutine/WaitWhileTests.cs @@ -0,0 +1,66 @@ +using GFramework.Core.coroutine.instructions; +using NUnit.Framework; + +namespace GFramework.Core.Tests.coroutine +{ + [TestFixture] + public class WaitWhileTests + { + [Test] + public void Constructor_WithNullPredicate_ThrowsArgumentNullException() + { + // Act & Assert + Assert.Throws(() => new WaitWhile(null!)); + } + + [Test] + public void IsDone_ReturnsInverseOfPredicateResult_True() + { + // Arrange + var condition = true; + var waitWhile = new WaitWhile(() => condition); + + // Act + condition = false; + + // Assert + Assert.That(waitWhile.IsDone, Is.True); + } + + [Test] + public void IsDone_ReturnsInverseOfPredicateResult_False() + { + // Arrange + var condition = false; + var waitWhile = new WaitWhile(() => condition); + + // Assert + Assert.That(waitWhile.IsDone, Is.True); // Because !false = true + } + + [Test] + public void IsDone_WhenPredicateReturnsTrue() + { + // Arrange + var condition = true; + var waitWhile = new WaitWhile(() => condition); + + // Assert + Assert.That(waitWhile.IsDone, Is.False); // Because !true = false + } + + [Test] + public void Update_DoesNotChangeState() + { + // Arrange + var condition = true; + var waitWhile = new WaitWhile(() => condition); + + // Act + waitWhile.Update(0.1); + + // Assert + Assert.That(waitWhile.IsDone, Is.False); + } + } +} \ No newline at end of file