using System.Reflection; using GFramework.Core.Abstractions.Cqrs; using GFramework.Core.Abstractions.Ioc; using GFramework.Core.Abstractions.Logging; using GFramework.Core.Architectures; using GFramework.Core.Ioc; using GFramework.Core.Logging; namespace GFramework.Core.Tests; /// /// 为测试项目提供对 CQRS 处理器真实注册入口的受控访问。 /// /// /// 测试应通过该入口驱动注册流程,而不是直接反射调用注册器的私有辅助方法, /// 这样可以覆盖生产启动路径中的程序集去重、日志记录与容错恢复行为。 /// internal static class CqrsTestRuntime { private static readonly Type CqrsHandlerRegistrarType = typeof(ArchitectureContext).Assembly .GetType( "GFramework.Core.Cqrs.Internal.CqrsHandlerRegistrar", throwOnError: true)! ?? throw new InvalidOperationException( "Failed to locate CqrsHandlerRegistrar type."); private static readonly MethodInfo RegisterHandlersMethod = CqrsHandlerRegistrarType .GetMethod( "RegisterHandlers", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static, binder: null, [ typeof(IIocContainer), typeof(IEnumerable), typeof(ILogger) ], modifiers: null) ?? throw new InvalidOperationException( "Failed to locate CqrsHandlerRegistrar.RegisterHandlers."); private static readonly Type CqrsDispatcherType = typeof(ArchitectureContext).Assembly .GetType( "GFramework.Core.Cqrs.Internal.CqrsDispatcher", throwOnError: true)! ?? throw new InvalidOperationException( "Failed to locate CqrsDispatcher type."); private static readonly ConstructorInfo CqrsDispatcherConstructor = CqrsDispatcherType.GetConstructor( BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, binder: null, [ typeof(IIocContainer), typeof(ILogger) ], modifiers: null) ?? throw new InvalidOperationException( "Failed to locate CqrsDispatcher constructor."); private static readonly Type DefaultCqrsHandlerRegistrarType = typeof(ArchitectureContext).Assembly .GetType( "GFramework.Core.Cqrs.Internal.DefaultCqrsHandlerRegistrar", throwOnError: true)! ?? throw new InvalidOperationException( "Failed to locate DefaultCqrsHandlerRegistrar type."); private static readonly ConstructorInfo DefaultCqrsHandlerRegistrarConstructor = DefaultCqrsHandlerRegistrarType.GetConstructor( BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, binder: null, [ typeof(IIocContainer), typeof(ILogger) ], modifiers: null) ?? throw new InvalidOperationException( "Failed to locate DefaultCqrsHandlerRegistrar constructor."); /// /// 为裸测试容器补齐默认 CQRS runtime seam。 /// 这使仅使用 的测试环境也能观察与生产路径一致的 runtime 行为, /// 而无需完整启动服务模块管理器。 /// /// 目标测试容器。 internal static void RegisterInfrastructure(MicrosoftDiContainer container) { ArgumentNullException.ThrowIfNull(container); var runtimeLogger = LoggerFactoryResolver.Provider.CreateLogger("CqrsDispatcher"); var registrarLogger = LoggerFactoryResolver.Provider.CreateLogger(nameof(CqrsTestRuntime)); var runtime = (ICqrsRuntime)CqrsDispatcherConstructor.Invoke([container, runtimeLogger]); var registrar = (ICqrsHandlerRegistrar)DefaultCqrsHandlerRegistrarConstructor.Invoke([container, registrarLogger]); container.Register(runtime); container.Register(registrar); } /// /// 通过与生产代码一致的注册入口扫描并注册指定程序集中的 CQRS 处理器。 /// /// 承载处理器映射的测试容器。 /// 要扫描的程序集集合。 internal static void RegisterHandlers(MicrosoftDiContainer container, params Assembly[] assemblies) { ArgumentNullException.ThrowIfNull(container); ArgumentNullException.ThrowIfNull(assemblies); RegisterInfrastructure(container); var logger = LoggerFactoryResolver.Provider.CreateLogger(nameof(CqrsTestRuntime)); RegisterHandlersMethod.Invoke( null, [container, assemblies.Where(static assembly => assembly is not null).Distinct().ToArray(), logger]); } }