test(coroutine): 添加协程指令单元测试并改进现有测试

- 为 Delay 指令添加完整的单元测试覆盖各种时间情况
- 为 WaitForCoroutine 指令添加单元测试验证协程等待功能
- 为 WaitForFrames 指令添加单元测试覆盖帧计数逻辑
- 为 WaitForTask<T> 指令添加单元测试包括异常处理场景
- 为 WaitOneFrame 指令添加单元测试验证单帧等待
- 为 WaitUntil 和 WaitWhile 指令添加单元测试覆盖谓词逻辑
- 将 WaitForMultipleEventsTests 中的异步方法标记为 async Task 类型
- 修改测试事件类的 Data 属性为可变的 set 访问器而不是只读 init
- 优化 WaitForMultipleEventsTests 中的断言注释描述
This commit is contained in:
GeWuYou 2026-02-10 23:35:14 +08:00 committed by gewuyou
parent 42a1ab0f29
commit e83dd278b3
8 changed files with 454 additions and 16 deletions

View File

@ -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);
}
}
}

View File

@ -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<IYieldInstruction> CreateDummyCoroutine()
{
return new List<IYieldInstruction>().GetEnumerator();
}
}
}

View File

@ -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);
}
}
}

View File

@ -34,7 +34,7 @@ namespace GFramework.Core.Tests.coroutine
}
[Test]
public Task FirstEventWins_WhenBothEventsFired()
public async Task FirstEventWins_WhenBothEventsFired()
{
// Arrange
var waitForMultipleEvents = new WaitForMultipleEvents<TestEvent1, TestEvent2>(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<TestEvent1, TestEvent2>(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<TestEvent1, TestEvent2>(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<TestEvent1, TestEvent2>(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<TestEvent1, TestEvent2>(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;
}
}
}

View File

@ -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<ArgumentNullException>(() => new WaitForTask<string>(null!));
}
[Test]
public async Task Constructor_WithCompletedTask_IsDoneImmediately()
{
// Arrange
var completedTask = Task.FromResult("test");
// Act
var waitForTask = new WaitForTask<string>(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<string>();
var incompleteTask = tcs.Task;
// Act
var waitForTask = new WaitForTask<string>(incompleteTask);
// Assert
Assert.That(waitForTask.IsDone, Is.False);
}
[Test]
public async Task TaskCompletes_CallbackSetsDoneFlag()
{
// Arrange
var tcs = new TaskCompletionSource<string>();
var task = tcs.Task;
var waitForTask = new WaitForTask<string>(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<string>(completedTask);
// Act
waitForTask.Update(0.1);
// Assert
Assert.That(waitForTask.IsDone, Is.True);
}
[Test]
public async Task TaskWithException_HoldsException()
{
// Arrange
var tcs = new TaskCompletionSource<string>();
var task = tcs.Task;
var waitForTask = new WaitForTask<string>(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<InvalidOperationException>());
}
}
}

View File

@ -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);
}
}
}

View File

@ -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<ArgumentNullException>(() => 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);
}
}
}

View File

@ -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<ArgumentNullException>(() => 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);
}
}
}