test(architecture): 添加异步架构测试并重构测试基类

- 创建 AsyncTestArchitecture 类用于异步测试
- 添加 AsyncTestSystem 实现异步初始化系统
- 创建 ArchitectureTestsBase 基类统一同步异步测试逻辑
- 实现 AsyncArchitectureTests 异步架构测试用例
- 将同步测试重构为继承自 ArchitectureTestsBase
- 移除重复的测试方法实现
- 重命名模型初始化状态属性为 Initialized
This commit is contained in:
GwWuYou 2026-01-02 10:53:55 +08:00
parent 67b0e83da4
commit 78da01878b
7 changed files with 289 additions and 104 deletions

View File

@ -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;
/// <summary>
/// 异步测试架构,用于测试异步模型和系统的初始化
/// </summary>
public class AsyncTestArchitecture : Architecture
{
/// <summary>
/// 初始化完成事件是否触发
/// </summary>
public bool ReadyEventFired { get; private set; }
/// <summary>
/// Init 方法是否调用
/// </summary>
public bool InitCalled { get; private set; }
/// <summary>
/// 阶段进入记录
/// </summary>
public List<ArchitecturePhase> PhaseHistory { get; } = new();
/// <summary>
/// 异步初始化架构
/// </summary>
protected override void Init()
{
InitCalled = true;
// 注册模型
RegisterModel(new AsyncTestModel());
// 注册系统
RegisterSystem(new AsyncTestSystem());
// 订阅 Ready 事件
Context.RegisterEvent<ArchitectureEvents.ArchitectureLifecycleReadyEvent>(_ => { ReadyEventFired = true; });
}
/// <summary>
/// 进入阶段时记录
/// </summary>
/// <param name="next"></param>
protected override void EnterPhase(ArchitecturePhase next)
{
base.EnterPhase(next);
PhaseHistory.Add(next);
}
}

View File

@ -14,7 +14,7 @@ public sealed class AsyncTestModel : IModel, IAsyncInitializable
/// <summary>
/// 获取模型是否已初始化的标志
/// </summary>
public bool Inited { get; private set; }
public bool Initialized { get; private set; }
/// <summary>
/// 异步初始化方法,模拟异步初始化过程
@ -23,7 +23,7 @@ public sealed class AsyncTestModel : IModel, IAsyncInitializable
public async Task InitializeAsync()
{
await Task.Delay(10);
Inited = true;
Initialized = true;
}
/// <summary>

View File

@ -14,14 +14,14 @@ public sealed class TestModel : IModel
/// <summary>
/// 获取模型是否已初始化的状态
/// </summary>
public bool Inited { get; private set; }
public bool Initialized { get; private set; }
/// <summary>
/// 初始化模型
/// </summary>
public void Init()
{
Inited = true;
Initialized = true;
}
public void SetContext(IArchitectureContext context)

View File

@ -0,0 +1,36 @@
using GFramework.Core.Abstractions.architecture;
using GFramework.Core.Abstractions.enums;
using GFramework.Core.Abstractions.system;
namespace GFramework.Core.Tests.system;
/// <summary>
/// 异步测试系统,实现 ISystem 和 IAsyncInitializable
/// </summary>
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)
{
}
}

View File

@ -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;
/// <summary>
/// 架构测试基类,封装同步/异步共通测试逻辑
/// </summary>
/// <typeparam name="TArchitecture">架构类型必须继承自Architecture</typeparam>
public abstract class ArchitectureTestsBase<TArchitecture> where TArchitecture : Architecture
{
protected TArchitecture? Architecture;
/// <summary>
/// 子类必须实现创建具体架构实例
/// </summary>
/// <returns>创建的架构实例</returns>
protected abstract TArchitecture CreateArchitecture();
/// <summary>
/// 子类必须实现初始化架构(同步或异步)
/// </summary>
/// <returns>异步初始化任务</returns>
protected abstract Task InitializeArchitecture();
/// <summary>
/// 测试设置方法,在每个测试开始前执行
/// 清理游戏上下文并创建架构实例
/// </summary>
[SetUp]
public void SetUp()
{
GameContext.Clear();
Architecture = CreateArchitecture();
}
/// <summary>
/// 测试清理方法,在每个测试结束后执行
/// 销毁架构实例并清理游戏上下文
/// </summary>
[TearDown]
public void TearDown()
{
try
{
Architecture?.Destroy();
}
finally
{
GameContext.Clear();
Architecture = null;
}
}
/// <summary>
/// 验证架构阶段顺序
/// </summary>
/// <returns>异步测试任务</returns>
[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<ArchitecturePhase>)phasesProperty!.GetValue(Architecture)!;
CollectionAssert.AreEqual(
new[]
{
ArchitecturePhase.BeforeModelInit,
ArchitecturePhase.AfterModelInit,
ArchitecturePhase.BeforeSystemInit,
ArchitecturePhase.AfterSystemInit,
ArchitecturePhase.Ready
},
phases
);
}
/// <summary>
/// 验证 Ready 后不能注册组件
/// </summary>
/// <returns>异步测试任务</returns>
[Test]
public async Task Registering_Components_AfterReady_Should_Throw()
{
await InitializeArchitecture();
// 根据架构类型验证注册组件时抛出异常
if (Architecture is SyncTestArchitecture syncArch)
{
Assert.Throws<InvalidOperationException>(() => syncArch.RegisterModel(new TestModel()));
Assert.Throws<InvalidOperationException>(() => syncArch.RegisterSystem(new TestSystem()));
}
else if (Architecture is AsyncTestArchitecture asyncArch)
{
Assert.Throws<InvalidOperationException>(() => asyncArch.RegisterModel(new AsyncTestModel()));
Assert.Throws<InvalidOperationException>(() => asyncArch.RegisterSystem(new AsyncTestSystem()));
}
}
/// <summary>
/// 验证销毁功能
/// </summary>
/// <returns>异步测试任务</returns>
[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<TestSystem>();
Assert.That(system!.DestroyCalled, Is.True);
}
else if (Architecture is AsyncTestArchitecture asyncArch)
{
var system = asyncArch.Context.GetSystem<AsyncTestSystem>();
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));
}
}

View File

@ -0,0 +1,30 @@
using GFramework.Core.Tests.architecture;
using NUnit.Framework;
namespace GFramework.Core.Tests.tests;
/// <summary>
/// 异步架构测试类,用于测试异步架构的相关功能
/// </summary>
/// <remarks>
/// 该测试类使用非并行执行模式,确保测试的隔离性
/// </remarks>
[TestFixture]
[NonParallelizable]
public class AsyncArchitectureTests : ArchitectureTestsBase<AsyncTestArchitecture>
{
/// <summary>
/// 创建异步测试架构实例
/// </summary>
/// <returns>AsyncTestArchitecture实例</returns>
protected override AsyncTestArchitecture CreateArchitecture() => new();
/// <summary>
/// 初始化架构的异步方法
/// </summary>
/// <returns>表示异步操作的Task</returns>
protected override async Task InitializeArchitecture()
{
await Architecture!.InitializeAsync();
}
}

View File

@ -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;
/// <summary>
/// 同步架构测试类,用于测试同步架构的初始化、生命周期和组件注册等功能
/// 同步架构测试类,用于测试同步架构的功能和行为
/// </summary>
/// <remarks>
/// 该测试类使用非并行执行模式,确保测试的隔离性和可靠性
/// </remarks>
[TestFixture]
[NonParallelizable]
public class SyncArchitectureTests
public class SyncArchitectureTests : ArchitectureTestsBase<SyncTestArchitecture>
{
/// <summary>
/// 测试初始化方法,清理游戏上下文并创建同步测试架构实例
/// 创建同步测试架构实例
/// </summary>
[SetUp]
public void SetUp()
{
GameContext.Clear();
_architecture = new SyncTestArchitecture();
}
/// <returns>SyncTestArchitecture实例</returns>
protected override SyncTestArchitecture CreateArchitecture() => new SyncTestArchitecture();
/// <summary>
/// 测试清理方法,销毁架构实例并清理游戏上下文
/// 初始化架构异步方法
/// </summary>
[TearDown]
public void TearDown()
/// <returns>表示异步操作的Task</returns>
protected override Task InitializeArchitecture()
{
try
{
_architecture?.Destroy();
}
finally
{
GameContext.Clear();
_architecture = null;
}
Architecture!.Initialize();
return Task.CompletedTask;
}
private SyncTestArchitecture? _architecture;
/// <summary>
/// 测试架构是否正确初始化所有组件
/// 验证初始化调用、运行时状态、架构阶段和模型系统注册
@ -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<TestModel>();
Assert.That(model, Is.Not.Null);
Assert.That(model!.Inited, Is.True);
Assert.That(model!.Initialized, Is.True);
var system = context.GetSystem<TestSystem>();
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);
}
/// <summary>
/// 测试架构是否按正确顺序进入各个阶段
/// 验证架构初始化过程中各阶段的执行顺序
/// </summary>
[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
);
}
/// <summary>
/// 测试在架构就绪后注册系统是否抛出异常(当不允许时)
/// </summary>
[Test]
public void RegisterSystem_AfterReady_Should_Throw_When_NotAllowed()
{
_architecture!.Initialize();
Assert.Throws<InvalidOperationException>(() => { _architecture.RegisterSystem(new TestSystem()); });
}
/// <summary>
/// 测试在架构就绪后注册模型是否抛出异常(当不允许时)
/// </summary>
[Test]
public void RegisterModel_AfterReady_Should_Throw_When_NotAllowed()
{
_architecture!.Initialize();
Assert.Throws<InvalidOperationException>(() => { _architecture.RegisterModel(new TestModel()); });
}
/// <summary>
/// 测试架构销毁功能,验证销毁后系统被正确销毁且架构进入销毁阶段
/// </summary>
[Test]
public void Architecture_Destroy_Should_Destroy_All_Systems_And_Enter_Destroyed()
{
_architecture!.Initialize();
_architecture.Destroy();
var system = _architecture.Context.GetSystem<TestSystem>();
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));
}
/// <summary>
/// 测试当模型初始化失败时架构是否停止初始化
/// </summary>
[Test]
public void Architecture_Should_Stop_Initialization_When_Model_Init_Fails()
{
_architecture!.RegisterModel(new FailingModel());
Architecture!.RegisterModel(new FailingModel());
Assert.Throws<InvalidOperationException>(() => { _architecture!.Initialize(); });
Assert.Throws<InvalidOperationException>(() => { Architecture!.Initialize(); });
}
}