From 78da01878bac540c4bba8b4d78e73803a536a7a9 Mon Sep 17 00:00:00 2001 From: GwWuYou <95328647+GeWuYou@users.noreply.github.com> Date: Fri, 2 Jan 2026 10:53:55 +0800 Subject: [PATCH] =?UTF-8?q?test(architecture):=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E5=BC=82=E6=AD=A5=E6=9E=B6=E6=9E=84=E6=B5=8B=E8=AF=95=E5=B9=B6?= =?UTF-8?q?=E9=87=8D=E6=9E=84=E6=B5=8B=E8=AF=95=E5=9F=BA=E7=B1=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 创建 AsyncTestArchitecture 类用于异步测试 - 添加 AsyncTestSystem 实现异步初始化系统 - 创建 ArchitectureTestsBase 基类统一同步异步测试逻辑 - 实现 AsyncArchitectureTests 异步架构测试用例 - 将同步测试重构为继承自 ArchitectureTestsBase - 移除重复的测试方法实现 - 重命名模型初始化状态属性为 Initialized --- .../architecture/AsyncTestArchitecture.cs | 55 +++++++ GFramework.Core.Tests/model/AsyncTestModel.cs | 4 +- GFramework.Core.Tests/model/TestModel.cs | 4 +- .../system/AsyncTestSystem.cs | 36 +++++ .../tests/ArchitectureTestsBase.cs | 141 ++++++++++++++++++ .../tests/AsyncArchitectureTests.cs | 30 ++++ .../tests/SyncArchitectureTests.cs | 123 +++------------ 7 files changed, 289 insertions(+), 104 deletions(-) create mode 100644 GFramework.Core.Tests/architecture/AsyncTestArchitecture.cs create mode 100644 GFramework.Core.Tests/system/AsyncTestSystem.cs create mode 100644 GFramework.Core.Tests/tests/ArchitectureTestsBase.cs create mode 100644 GFramework.Core.Tests/tests/AsyncArchitectureTests.cs diff --git a/GFramework.Core.Tests/architecture/AsyncTestArchitecture.cs b/GFramework.Core.Tests/architecture/AsyncTestArchitecture.cs new file mode 100644 index 0000000..8065271 --- /dev/null +++ b/GFramework.Core.Tests/architecture/AsyncTestArchitecture.cs @@ -0,0 +1,55 @@ +using GFramework.Core.Abstractions.enums; +using GFramework.Core.architecture; +using GFramework.Core.events; +using GFramework.Core.Tests.model; +using GFramework.Core.Tests.system; + +namespace GFramework.Core.Tests.architecture; + +/// +/// 异步测试架构,用于测试异步模型和系统的初始化 +/// +public class AsyncTestArchitecture : Architecture +{ + /// + /// 初始化完成事件是否触发 + /// + public bool ReadyEventFired { get; private set; } + + /// + /// Init 方法是否调用 + /// + public bool InitCalled { get; private set; } + + /// + /// 阶段进入记录 + /// + public List PhaseHistory { get; } = new(); + + /// + /// 异步初始化架构 + /// + protected override void Init() + { + InitCalled = true; + + // 注册模型 + RegisterModel(new AsyncTestModel()); + + // 注册系统 + RegisterSystem(new AsyncTestSystem()); + + // 订阅 Ready 事件 + Context.RegisterEvent(_ => { ReadyEventFired = true; }); + } + + /// + /// 进入阶段时记录 + /// + /// + protected override void EnterPhase(ArchitecturePhase next) + { + base.EnterPhase(next); + PhaseHistory.Add(next); + } +} \ No newline at end of file diff --git a/GFramework.Core.Tests/model/AsyncTestModel.cs b/GFramework.Core.Tests/model/AsyncTestModel.cs index 3088a60..7d45c3a 100644 --- a/GFramework.Core.Tests/model/AsyncTestModel.cs +++ b/GFramework.Core.Tests/model/AsyncTestModel.cs @@ -14,7 +14,7 @@ public sealed class AsyncTestModel : IModel, IAsyncInitializable /// /// 获取模型是否已初始化的标志 /// - public bool Inited { get; private set; } + public bool Initialized { get; private set; } /// /// 异步初始化方法,模拟异步初始化过程 @@ -23,7 +23,7 @@ public sealed class AsyncTestModel : IModel, IAsyncInitializable public async Task InitializeAsync() { await Task.Delay(10); - Inited = true; + Initialized = true; } /// diff --git a/GFramework.Core.Tests/model/TestModel.cs b/GFramework.Core.Tests/model/TestModel.cs index cc3dc37..e9c59a5 100644 --- a/GFramework.Core.Tests/model/TestModel.cs +++ b/GFramework.Core.Tests/model/TestModel.cs @@ -14,14 +14,14 @@ public sealed class TestModel : IModel /// /// 获取模型是否已初始化的状态 /// - public bool Inited { get; private set; } + public bool Initialized { get; private set; } /// /// 初始化模型 /// public void Init() { - Inited = true; + Initialized = true; } public void SetContext(IArchitectureContext context) diff --git a/GFramework.Core.Tests/system/AsyncTestSystem.cs b/GFramework.Core.Tests/system/AsyncTestSystem.cs new file mode 100644 index 0000000..680b0b9 --- /dev/null +++ b/GFramework.Core.Tests/system/AsyncTestSystem.cs @@ -0,0 +1,36 @@ +using GFramework.Core.Abstractions.architecture; +using GFramework.Core.Abstractions.enums; +using GFramework.Core.Abstractions.system; + +namespace GFramework.Core.Tests.system; + +/// +/// 异步测试系统,实现 ISystem 和 IAsyncInitializable +/// +public sealed class AsyncTestSystem : ISystem, IAsyncInitializable +{ + private IArchitectureContext _context = null!; + public bool Initialized { get; private set; } + public bool DestroyCalled { get; private set; } + + public async Task InitializeAsync() + { + await Task.Delay(10); + Initialized = true; + } + + public void SetContext(IArchitectureContext context) => _context = context; + public IArchitectureContext GetContext() => _context; + + public void Init() + { + // 同步 Init 不应该被调用 + throw new InvalidOperationException("Sync Init should not be called"); + } + + public void Destroy() => DestroyCalled = true; + + public void OnArchitecturePhase(ArchitecturePhase phase) + { + } +} \ No newline at end of file diff --git a/GFramework.Core.Tests/tests/ArchitectureTestsBase.cs b/GFramework.Core.Tests/tests/ArchitectureTestsBase.cs new file mode 100644 index 0000000..3ccb9ee --- /dev/null +++ b/GFramework.Core.Tests/tests/ArchitectureTestsBase.cs @@ -0,0 +1,141 @@ +using System.Reflection; +using GFramework.Core.Abstractions.enums; +using GFramework.Core.architecture; +using GFramework.Core.Tests.architecture; +using GFramework.Core.Tests.model; +using GFramework.Core.Tests.system; +using NUnit.Framework; +using NUnit.Framework.Legacy; + +namespace GFramework.Core.Tests.tests; + +/// +/// 架构测试基类,封装同步/异步共通测试逻辑 +/// +/// 架构类型,必须继承自Architecture +public abstract class ArchitectureTestsBase where TArchitecture : Architecture +{ + protected TArchitecture? Architecture; + + /// + /// 子类必须实现创建具体架构实例 + /// + /// 创建的架构实例 + protected abstract TArchitecture CreateArchitecture(); + + /// + /// 子类必须实现初始化架构(同步或异步) + /// + /// 异步初始化任务 + protected abstract Task InitializeArchitecture(); + + /// + /// 测试设置方法,在每个测试开始前执行 + /// 清理游戏上下文并创建架构实例 + /// + [SetUp] + public void SetUp() + { + GameContext.Clear(); + Architecture = CreateArchitecture(); + } + + /// + /// 测试清理方法,在每个测试结束后执行 + /// 销毁架构实例并清理游戏上下文 + /// + [TearDown] + public void TearDown() + { + try + { + Architecture?.Destroy(); + } + finally + { + GameContext.Clear(); + Architecture = null; + } + } + + /// + /// 验证架构阶段顺序 + /// + /// 异步测试任务 + [Test] + public async Task Architecture_Should_Enter_Phases_In_Correct_Order() + { + await InitializeArchitecture(); + + // 通过反射获取架构的阶段历史记录 + var phasesProperty = typeof(TArchitecture) + .GetProperty("PhaseHistory", BindingFlags.Instance | BindingFlags.Public); + + var phases = (List)phasesProperty!.GetValue(Architecture)!; + + CollectionAssert.AreEqual( + new[] + { + ArchitecturePhase.BeforeModelInit, + ArchitecturePhase.AfterModelInit, + ArchitecturePhase.BeforeSystemInit, + ArchitecturePhase.AfterSystemInit, + ArchitecturePhase.Ready + }, + phases + ); + } + + /// + /// 验证 Ready 后不能注册组件 + /// + /// 异步测试任务 + [Test] + public async Task Registering_Components_AfterReady_Should_Throw() + { + await InitializeArchitecture(); + + // 根据架构类型验证注册组件时抛出异常 + if (Architecture is SyncTestArchitecture syncArch) + { + Assert.Throws(() => syncArch.RegisterModel(new TestModel())); + Assert.Throws(() => syncArch.RegisterSystem(new TestSystem())); + } + else if (Architecture is AsyncTestArchitecture asyncArch) + { + Assert.Throws(() => asyncArch.RegisterModel(new AsyncTestModel())); + Assert.Throws(() => asyncArch.RegisterSystem(new AsyncTestSystem())); + } + } + + /// + /// 验证销毁功能 + /// + /// 异步测试任务 + [Test] + public async Task Architecture_Destroy_Should_Destroy_All_Systems_And_Enter_Destroyed() + { + await InitializeArchitecture(); + + Architecture!.Destroy(); + + // 验证系统是否被正确销毁 + if (Architecture is SyncTestArchitecture syncArch) + { + var system = syncArch.Context.GetSystem(); + Assert.That(system!.DestroyCalled, Is.True); + } + else if (Architecture is AsyncTestArchitecture asyncArch) + { + var system = asyncArch.Context.GetSystem(); + Assert.That(system!.DestroyCalled, Is.True); + } + + // 通过反射验证当前阶段为销毁状态 + var phaseProperty = typeof(TArchitecture) + .GetProperty("CurrentPhase", BindingFlags.Instance | BindingFlags.NonPublic); + + var phase = (ArchitecturePhase)phaseProperty!.GetValue(Architecture)!; + Assert.That(phase, Is.EqualTo(ArchitecturePhase.Destroyed)); + } +} \ No newline at end of file diff --git a/GFramework.Core.Tests/tests/AsyncArchitectureTests.cs b/GFramework.Core.Tests/tests/AsyncArchitectureTests.cs new file mode 100644 index 0000000..c01d6ba --- /dev/null +++ b/GFramework.Core.Tests/tests/AsyncArchitectureTests.cs @@ -0,0 +1,30 @@ +using GFramework.Core.Tests.architecture; +using NUnit.Framework; + +namespace GFramework.Core.Tests.tests; + +/// +/// 异步架构测试类,用于测试异步架构的相关功能 +/// +/// +/// 该测试类使用非并行执行模式,确保测试的隔离性 +/// +[TestFixture] +[NonParallelizable] +public class AsyncArchitectureTests : ArchitectureTestsBase +{ + /// + /// 创建异步测试架构实例 + /// + /// AsyncTestArchitecture实例 + protected override AsyncTestArchitecture CreateArchitecture() => new(); + + /// + /// 初始化架构的异步方法 + /// + /// 表示异步操作的Task + protected override async Task InitializeArchitecture() + { + await Architecture!.InitializeAsync(); + } +} \ No newline at end of file diff --git a/GFramework.Core.Tests/tests/SyncArchitectureTests.cs b/GFramework.Core.Tests/tests/SyncArchitectureTests.cs index b8d4eed..bbe266f 100644 --- a/GFramework.Core.Tests/tests/SyncArchitectureTests.cs +++ b/GFramework.Core.Tests/tests/SyncArchitectureTests.cs @@ -5,46 +5,35 @@ using GFramework.Core.Tests.architecture; using GFramework.Core.Tests.model; using GFramework.Core.Tests.system; using NUnit.Framework; -using NUnit.Framework.Legacy; namespace GFramework.Core.Tests.tests; /// -/// 同步架构测试类,用于测试同步架构的初始化、生命周期和组件注册等功能 +/// 同步架构测试类,用于测试同步架构的功能和行为 /// +/// +/// 该测试类使用非并行执行模式,确保测试的隔离性和可靠性 +/// [TestFixture] [NonParallelizable] -public class SyncArchitectureTests +public class SyncArchitectureTests : ArchitectureTestsBase { /// - /// 测试初始化方法,清理游戏上下文并创建同步测试架构实例 + /// 创建同步测试架构实例 /// - [SetUp] - public void SetUp() - { - GameContext.Clear(); - _architecture = new SyncTestArchitecture(); - } + /// SyncTestArchitecture实例 + protected override SyncTestArchitecture CreateArchitecture() => new SyncTestArchitecture(); /// - /// 测试清理方法,销毁架构实例并清理游戏上下文 + /// 初始化架构异步方法 /// - [TearDown] - public void TearDown() + /// 表示异步操作的Task + protected override Task InitializeArchitecture() { - try - { - _architecture?.Destroy(); - } - finally - { - GameContext.Clear(); - _architecture = null; - } + Architecture!.Initialize(); + return Task.CompletedTask; } - private SyncTestArchitecture? _architecture; - /// /// 测试架构是否正确初始化所有组件 /// 验证初始化调用、运行时状态、架构阶段和模型系统注册 @@ -53,25 +42,25 @@ public class SyncArchitectureTests public void Architecture_Should_Initialize_All_Components_Correctly() { // Act - _architecture!.Initialize(); + Architecture!.Initialize(); // Assert - Assert.That(_architecture.InitCalled, Is.True); + Assert.That(Architecture.InitCalled, Is.True); - Assert.That(_architecture.Runtime, Is.Not.Null); + Assert.That(Architecture.Runtime, Is.Not.Null); // 通过反射获取当前架构阶段 var phaseProperty = typeof(Architecture) .GetProperty("CurrentPhase", BindingFlags.Instance | BindingFlags.NonPublic); - var phase = (ArchitecturePhase)phaseProperty!.GetValue(_architecture)!; + var phase = (ArchitecturePhase)phaseProperty!.GetValue(Architecture)!; Assert.That(phase, Is.EqualTo(ArchitecturePhase.Ready)); - var context = _architecture.Context; + var context = Architecture.Context; var model = context.GetModel(); Assert.That(model, Is.Not.Null); - Assert.That(model!.Inited, Is.True); + Assert.That(model!.Initialized, Is.True); var system = context.GetSystem(); Assert.That(system, Is.Not.Null); @@ -85,86 +74,20 @@ public class SyncArchitectureTests public void Architecture_Should_Register_Context_By_Type() { // Act - _architecture!.Initialize(); - var ctx = GameContext.GetByType(_architecture!.GetType()); + Architecture!.Initialize(); + var ctx = GameContext.GetByType(Architecture!.GetType()); Assert.That(ctx, Is.Not.Null); } - /// - /// 测试架构是否按正确顺序进入各个阶段 - /// 验证架构初始化过程中各阶段的执行顺序 - /// - [Test] - public void Architecture_Should_Enter_Phases_In_Correct_Order() - { - _architecture!.Initialize(); - - var phases = _architecture.PhaseHistory; - - CollectionAssert.AreEqual( - new[] - { - ArchitecturePhase.BeforeModelInit, - ArchitecturePhase.AfterModelInit, - ArchitecturePhase.BeforeSystemInit, - ArchitecturePhase.AfterSystemInit, - ArchitecturePhase.Ready - }, - phases - ); - } - - /// - /// 测试在架构就绪后注册系统是否抛出异常(当不允许时) - /// - [Test] - public void RegisterSystem_AfterReady_Should_Throw_When_NotAllowed() - { - _architecture!.Initialize(); - - Assert.Throws(() => { _architecture.RegisterSystem(new TestSystem()); }); - } - - /// - /// 测试在架构就绪后注册模型是否抛出异常(当不允许时) - /// - [Test] - public void RegisterModel_AfterReady_Should_Throw_When_NotAllowed() - { - _architecture!.Initialize(); - - Assert.Throws(() => { _architecture.RegisterModel(new TestModel()); }); - } - - /// - /// 测试架构销毁功能,验证销毁后系统被正确销毁且架构进入销毁阶段 - /// - [Test] - public void Architecture_Destroy_Should_Destroy_All_Systems_And_Enter_Destroyed() - { - _architecture!.Initialize(); - _architecture.Destroy(); - - var system = _architecture.Context.GetSystem(); - Assert.That(system!.DestroyCalled, Is.True); - - // 通过反射获取当前架构阶段 - var phaseProperty = typeof(Architecture) - .GetProperty("CurrentPhase", BindingFlags.Instance | BindingFlags.NonPublic); - - var phase = (ArchitecturePhase)phaseProperty!.GetValue(_architecture)!; - Assert.That(phase, Is.EqualTo(ArchitecturePhase.Destroyed)); - } - /// /// 测试当模型初始化失败时架构是否停止初始化 /// [Test] public void Architecture_Should_Stop_Initialization_When_Model_Init_Fails() { - _architecture!.RegisterModel(new FailingModel()); + Architecture!.RegisterModel(new FailingModel()); - Assert.Throws(() => { _architecture!.Initialize(); }); + Assert.Throws(() => { Architecture!.Initialize(); }); } } \ No newline at end of file