GFramework/GFramework.Core.Tests/Architectures/ArchitectureComponentRegistryBehaviorTests.cs
GeWuYou bb2b3a0c60 refactor(arch): 重构架构组件注册机制
- 将组件注册逻辑提取到独立的 ArchitectureComponentRegistry 类中
- 实现 ArchitectureComponentActivator 来支持注册阶段实例化组件
- 更新系统和模型注册文档说明,明确在注册阶段创建实例并参与初始化
- 修复类型注册在架构准备就绪后的行为一致性问题
- 添加完整的组件注册行为测试覆盖实例注册、工厂注册和生命周期管理
- 优化依赖注入解析机制,支持构造函数依赖和单例缓存
2026-04-05 11:01:50 +08:00

472 lines
15 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using GFramework.Core.Abstractions.Architectures;
using GFramework.Core.Abstractions.Enums;
using GFramework.Core.Abstractions.Model;
using GFramework.Core.Abstractions.Systems;
using GFramework.Core.Abstractions.Utility;
using GFramework.Core.Architectures;
using GFramework.Core.Logging;
namespace GFramework.Core.Tests.Architectures;
/// <summary>
/// 验证 Architecture 通过 <c>ArchitectureComponentRegistry</c> 暴露出的组件注册行为。
/// 这些测试覆盖实例注册、工厂注册、上下文注入、生命周期初始化和 Ready 后注册约束,
/// 用于保护组件注册器在继续重构后的既有契约。
/// </summary>
[TestFixture]
public class ArchitectureComponentRegistryBehaviorTests
{
/// <summary>
/// 初始化日志工厂和全局上下文状态。
/// </summary>
[SetUp]
public void SetUp()
{
LoggerFactoryResolver.Provider = new ConsoleLoggerFactoryProvider();
GameContext.Clear();
}
/// <summary>
/// 清理测试过程中绑定到全局表的架构上下文。
/// </summary>
[TearDown]
public void TearDown()
{
GameContext.Clear();
}
/// <summary>
/// 验证系统实例注册会注入上下文并参与生命周期初始化。
/// </summary>
[Test]
public async Task RegisterSystem_Instance_Should_Set_Context_And_Initialize_System()
{
var system = new TrackingSystem();
var architecture = new RegistryTestArchitecture(target => target.RegisterSystem(system));
await architecture.InitializeAsync();
Assert.Multiple(() =>
{
Assert.That(system.GetContext(), Is.SameAs(architecture.Context));
Assert.That(system.InitializeCallCount, Is.EqualTo(1));
Assert.That(architecture.Context.GetSystem<TrackingSystem>(), Is.SameAs(system));
});
await architecture.DestroyAsync();
}
/// <summary>
/// 验证模型实例注册会注入上下文并参与生命周期初始化。
/// </summary>
[Test]
public async Task RegisterModel_Instance_Should_Set_Context_And_Initialize_Model()
{
var model = new TrackingModel();
var architecture = new RegistryTestArchitecture(target => target.RegisterModel(model));
await architecture.InitializeAsync();
Assert.Multiple(() =>
{
Assert.That(model.GetContext(), Is.SameAs(architecture.Context));
Assert.That(model.InitializeCallCount, Is.EqualTo(1));
Assert.That(architecture.Context.GetModel<TrackingModel>(), Is.SameAs(model));
});
await architecture.DestroyAsync();
}
/// <summary>
/// 验证上下文工具注册会注入上下文并参与生命周期初始化。
/// </summary>
[Test]
public async Task RegisterUtility_Instance_Should_Set_Context_For_ContextUtility()
{
var utility = new TrackingContextUtility();
var architecture = new RegistryTestArchitecture(target => target.RegisterUtility(utility));
await architecture.InitializeAsync();
Assert.Multiple(() =>
{
Assert.That(utility.GetContext(), Is.SameAs(architecture.Context));
Assert.That(utility.InitializeCallCount, Is.EqualTo(1));
Assert.That(architecture.Context.GetUtility<TrackingContextUtility>(), Is.SameAs(utility));
});
await architecture.DestroyAsync();
}
/// <summary>
/// 验证普通工具的工厂注册会在首次解析时创建单例并执行创建回调。
/// </summary>
[Test]
public async Task RegisterUtility_Type_Should_Create_Singleton_And_Invoke_Callback()
{
FactoryCreatedUtility? callbackInstance = null;
var architecture = new RegistryTestArchitecture(target =>
target.RegisterUtility<FactoryCreatedUtility>(created => callbackInstance = created));
await architecture.InitializeAsync();
var first = architecture.Context.GetUtility<FactoryCreatedUtility>();
var second = architecture.Context.GetUtility<FactoryCreatedUtility>();
Assert.Multiple(() =>
{
Assert.That(callbackInstance, Is.SameAs(first));
Assert.That(second, Is.SameAs(first));
});
await architecture.DestroyAsync();
}
/// <summary>
/// 验证系统类型注册会在初始化期间物化实例、注入构造函数依赖并执行创建回调。
/// </summary>
[Test]
public async Task RegisterSystem_Type_Should_Create_Instance_During_Initialization()
{
var dependency = new ConstructorDependency("system-dependency");
FactoryCreatedSystem? callbackInstance = null;
var architecture = new RegistryTestArchitecture(
target => target.RegisterSystem<FactoryCreatedSystem>(created => callbackInstance = created),
services => services.AddSingleton(dependency));
await architecture.InitializeAsync();
var resolved = architecture.Context.GetSystem<FactoryCreatedSystem>();
Assert.Multiple(() =>
{
Assert.That(callbackInstance, Is.Not.Null);
Assert.That(resolved, Is.SameAs(callbackInstance));
Assert.That(resolved.Dependency, Is.SameAs(dependency));
Assert.That(resolved.GetContext(), Is.SameAs(architecture.Context));
Assert.That(resolved.InitializeCallCount, Is.EqualTo(1));
});
await architecture.DestroyAsync();
}
/// <summary>
/// 验证模型类型注册会在初始化期间物化实例、注入构造函数依赖并执行创建回调。
/// </summary>
[Test]
public async Task RegisterModel_Type_Should_Create_Instance_During_Initialization()
{
var dependency = new ConstructorDependency("model-dependency");
FactoryCreatedModel? callbackInstance = null;
var architecture = new RegistryTestArchitecture(
target => target.RegisterModel<FactoryCreatedModel>(created => callbackInstance = created),
services => services.AddSingleton(dependency));
await architecture.InitializeAsync();
var resolved = architecture.Context.GetModel<FactoryCreatedModel>();
Assert.Multiple(() =>
{
Assert.That(callbackInstance, Is.Not.Null);
Assert.That(resolved, Is.SameAs(callbackInstance));
Assert.That(resolved.Dependency, Is.SameAs(dependency));
Assert.That(resolved.GetContext(), Is.SameAs(architecture.Context));
Assert.That(resolved.InitializeCallCount, Is.EqualTo(1));
});
await architecture.DestroyAsync();
}
/// <summary>
/// 验证 Ready 阶段后不允许继续注册 Utility保持与系统和模型一致的约束。
/// </summary>
[Test]
public async Task RegisterUtility_After_Ready_Should_Throw_InvalidOperationException()
{
var architecture = new RegistryTestArchitecture(_ => { });
await architecture.InitializeAsync();
Assert.That(
() => architecture.RegisterUtility(new TrackingContextUtility()),
Throws.InvalidOperationException.With.Message.EqualTo(
"Cannot register utility after Architecture is Ready"));
await architecture.DestroyAsync();
}
/// <summary>
/// 用于测试组件注册行为的最小架构实现。
/// </summary>
private sealed class RegistryTestArchitecture : Architecture
{
private readonly Action<IServiceCollection>? _configurator;
private readonly Action<RegistryTestArchitecture> _registrationAction;
/// <summary>
/// 创建一个可选地附带服务配置逻辑的测试架构。
/// </summary>
/// <param name="registrationAction">初始化阶段执行的组件注册逻辑。</param>
/// <param name="configurator">初始化前执行的服务配置逻辑。</param>
public RegistryTestArchitecture(
Action<RegistryTestArchitecture> registrationAction,
Action<IServiceCollection>? configurator = null)
{
_registrationAction = registrationAction;
_configurator = configurator;
}
/// <summary>
/// 返回测试注入的服务配置逻辑。
/// </summary>
public override Action<IServiceCollection>? Configurator => _configurator;
/// <summary>
/// 在初始化阶段执行测试注入的注册逻辑。
/// </summary>
protected override void OnInitialize()
{
_registrationAction(this);
}
}
/// <summary>
/// 记录初始化与上下文注入情况的测试系统。
/// </summary>
private sealed class TrackingSystem : ISystem
{
private IArchitectureContext _context = null!;
/// <summary>
/// 获取系统初始化调用次数。
/// </summary>
public int InitializeCallCount { get; private set; }
/// <summary>
/// 记录初始化调用。
/// </summary>
public void Initialize()
{
InitializeCallCount++;
}
/// <summary>
/// 该测试系统不关心阶段变更。
/// </summary>
/// <param name="phase">当前架构阶段。</param>
public void OnArchitecturePhase(ArchitecturePhase phase)
{
}
/// <summary>
/// 存储注入的架构上下文。
/// </summary>
/// <param name="context">架构上下文。</param>
public void SetContext(IArchitectureContext context)
{
_context = context;
}
/// <summary>
/// 返回当前持有的架构上下文。
/// </summary>
public IArchitectureContext GetContext()
{
return _context;
}
/// <summary>
/// 该测试系统没有额外销毁逻辑。
/// </summary>
public void Destroy()
{
}
}
/// <summary>
/// 记录初始化与上下文注入情况的测试模型。
/// </summary>
private sealed class TrackingModel : IModel
{
private IArchitectureContext _context = null!;
/// <summary>
/// 获取模型初始化调用次数。
/// </summary>
public int InitializeCallCount { get; private set; }
/// <summary>
/// 记录初始化调用。
/// </summary>
public void Initialize()
{
InitializeCallCount++;
}
/// <summary>
/// 该测试模型不关心阶段变更。
/// </summary>
/// <param name="phase">当前架构阶段。</param>
public void OnArchitecturePhase(ArchitecturePhase phase)
{
}
/// <summary>
/// 存储注入的架构上下文。
/// </summary>
/// <param name="context">架构上下文。</param>
public void SetContext(IArchitectureContext context)
{
_context = context;
}
/// <summary>
/// 返回当前持有的架构上下文。
/// </summary>
public IArchitectureContext GetContext()
{
return _context;
}
}
/// <summary>
/// 记录初始化与上下文注入情况的测试上下文工具。
/// </summary>
private sealed class TrackingContextUtility : IContextUtility
{
private IArchitectureContext _context = null!;
/// <summary>
/// 获取工具初始化调用次数。
/// </summary>
public int InitializeCallCount { get; private set; }
/// <summary>
/// 记录初始化调用。
/// </summary>
public void Initialize()
{
InitializeCallCount++;
}
/// <summary>
/// 存储注入的架构上下文。
/// </summary>
/// <param name="context">架构上下文。</param>
public void SetContext(IArchitectureContext context)
{
_context = context;
}
/// <summary>
/// 返回当前持有的架构上下文。
/// </summary>
public IArchitectureContext GetContext()
{
return _context;
}
/// <summary>
/// 该测试工具没有额外销毁逻辑。
/// </summary>
public void Destroy()
{
}
}
/// <summary>
/// 用于验证普通工厂注册路径的简单工具。
/// </summary>
private sealed class FactoryCreatedUtility : IUtility
{
}
/// <summary>
/// 用于验证构造函数依赖注入的简单依赖对象。
/// </summary>
private sealed class ConstructorDependency(string name)
{
/// <summary>
/// 获取依赖对象名称。
/// </summary>
public string Name { get; } = name;
}
/// <summary>
/// 用于验证系统类型注册路径的工厂创建系统。
/// </summary>
private sealed class FactoryCreatedSystem(ConstructorDependency dependency) : ISystem
{
private IArchitectureContext _context = null!;
/// <summary>
/// 获取构造函数注入的依赖对象。
/// </summary>
public ConstructorDependency Dependency { get; } = dependency;
/// <summary>
/// 获取初始化调用次数。
/// </summary>
public int InitializeCallCount { get; private set; }
public void Initialize()
{
InitializeCallCount++;
}
public void Destroy()
{
}
public void OnArchitecturePhase(ArchitecturePhase phase)
{
}
public void SetContext(IArchitectureContext context)
{
_context = context;
}
public IArchitectureContext GetContext()
{
return _context;
}
}
/// <summary>
/// 用于验证模型类型注册路径的工厂创建模型。
/// </summary>
private sealed class FactoryCreatedModel(ConstructorDependency dependency) : IModel
{
private IArchitectureContext _context = null!;
/// <summary>
/// 获取构造函数注入的依赖对象。
/// </summary>
public ConstructorDependency Dependency { get; } = dependency;
/// <summary>
/// 获取初始化调用次数。
/// </summary>
public int InitializeCallCount { get; private set; }
public void Initialize()
{
InitializeCallCount++;
}
public void OnArchitecturePhase(ArchitecturePhase phase)
{
}
public void SetContext(IArchitectureContext context)
{
_context = context;
}
public IArchitectureContext GetContext()
{
return _context;
}
}
}