From b5ac8b2c346b95d21d39b06c3b05ee2419379ff6 Mon Sep 17 00:00:00 2001 From: GeWuYou <95328647+GeWuYou@users.noreply.github.com> Date: Sat, 28 Mar 2026 13:03:56 +0800 Subject: [PATCH] =?UTF-8?q?refactor(core):=20=E9=87=8D=E6=9E=84=E4=B8=8A?= =?UTF-8?q?=E4=B8=8B=E6=96=87=E6=84=9F=E7=9F=A5=E6=9C=8D=E5=8A=A1=E6=89=A9?= =?UTF-8?q?=E5=B1=95=E4=BB=A5=E6=94=B9=E8=BF=9B=E7=BB=84=E4=BB=B6=E8=8E=B7?= =?UTF-8?q?=E5=8F=96=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 引入通用的 GetRequiredComponent 方法来统一服务、系统、模型和工具的获取逻辑 - 添加对架构上下文组件的空值检查和异常处理 - 实现更清晰的错误消息以指示未注册的组件类型 - 为所有组件类型(服务、系统、模型、工具)添加缺失的单元测试 - 测试验证当上下文返回空组件时抛出正确的 InvalidOperationException - 改进代码可维护性并减少重复的获取组件逻辑 --- .../ContextAwareServiceExtensionsTests.cs | 59 +++++++++++++++++-- .../ContextAwareServiceExtensions.cs | 23 ++++++-- 2 files changed, 73 insertions(+), 9 deletions(-) diff --git a/GFramework.Core.Tests/Rule/ContextAwareServiceExtensionsTests.cs b/GFramework.Core.Tests/Rule/ContextAwareServiceExtensionsTests.cs index 0a95d13..b0f066f 100644 --- a/GFramework.Core.Tests/Rule/ContextAwareServiceExtensionsTests.cs +++ b/GFramework.Core.Tests/Rule/ContextAwareServiceExtensionsTests.cs @@ -5,9 +5,9 @@ using GFramework.Core.Abstractions.Rule; using GFramework.Core.Abstractions.Systems; using GFramework.Core.Abstractions.Utility; using GFramework.Core.Architectures; -using GFramework.Core.Extensions; using GFramework.Core.Ioc; using GFramework.Core.Rule; +using GFramework.Core.Tests.Architectures; namespace GFramework.Core.Tests.Rule; @@ -18,6 +18,11 @@ namespace GFramework.Core.Tests.Rule; [TestFixture] public class ContextAwareServiceExtensionsTests { + private MicrosoftDiContainer _container = null!; + private ArchitectureContext _context = null!; + + private TestContextAware _contextAware = null!; + [SetUp] public void SetUp() { @@ -34,10 +39,6 @@ public class ContextAwareServiceExtensionsTests _container.Clear(); } - private TestContextAware _contextAware = null!; - private ArchitectureContext _context = null!; - private MicrosoftDiContainer _container = null!; - [Test] public void GetService_Should_Return_Registered_Service() { @@ -53,6 +54,18 @@ public class ContextAwareServiceExtensionsTests Assert.That(result, Is.SameAs(service)); } + [Test] + public void GetService_Should_Throw_When_Context_Returns_Null_Service() + { + // Arrange + var contextAware = new TestContextAware(); + ((IContextAware)contextAware).SetContext(new TestArchitectureContextV3()); + + // Act / Assert + Assert.That(() => contextAware.GetService(), + Throws.InvalidOperationException.With.Message.Contains("Service")); + } + [Test] public void GetSystem_Should_Return_Registered_System() { @@ -68,6 +81,18 @@ public class ContextAwareServiceExtensionsTests Assert.That(result, Is.SameAs(system)); } + [Test] + public void GetSystem_Should_Throw_When_Context_Returns_Null_System() + { + // Arrange + var contextAware = new TestContextAware(); + ((IContextAware)contextAware).SetContext(new TestArchitectureContextV3()); + + // Act / Assert + Assert.That(() => contextAware.GetSystem(), + Throws.InvalidOperationException.With.Message.Contains("System")); + } + [Test] public void GetModel_Should_Return_Registered_Model() { @@ -83,6 +108,18 @@ public class ContextAwareServiceExtensionsTests Assert.That(result, Is.SameAs(model)); } + [Test] + public void GetModel_Should_Throw_When_Context_Returns_Null_Model() + { + // Arrange + var contextAware = new TestContextAware(); + ((IContextAware)contextAware).SetContext(new TestArchitectureContextV3()); + + // Act / Assert + Assert.That(() => contextAware.GetModel(), + Throws.InvalidOperationException.With.Message.Contains("Model")); + } + [Test] public void GetUtility_Should_Return_Registered_Utility() { @@ -98,6 +135,18 @@ public class ContextAwareServiceExtensionsTests Assert.That(result, Is.SameAs(utility)); } + [Test] + public void GetUtility_Should_Throw_When_Context_Returns_Null_Utility() + { + // Arrange + var contextAware = new TestContextAware(); + ((IContextAware)contextAware).SetContext(new TestArchitectureContextV3()); + + // Act / Assert + Assert.That(() => contextAware.GetUtility(), + Throws.InvalidOperationException.With.Message.Contains("Utility")); + } + [Test] public void GetServices_Should_Return_All_Registered_Services() { diff --git a/GFramework.Core/Extensions/ContextAwareServiceExtensions.cs b/GFramework.Core/Extensions/ContextAwareServiceExtensions.cs index 27e16e7..cb82199 100644 --- a/GFramework.Core/Extensions/ContextAwareServiceExtensions.cs +++ b/GFramework.Core/Extensions/ContextAwareServiceExtensions.cs @@ -1,3 +1,4 @@ +using GFramework.Core.Abstractions.Architectures; using GFramework.Core.Abstractions.Model; using GFramework.Core.Abstractions.Rule; using GFramework.Core.Abstractions.Systems; @@ -25,7 +26,8 @@ public static class ContextAwareServiceExtensions { ArgumentNullException.ThrowIfNull(contextAware); var context = contextAware.GetContext(); - return context.GetService(); + return GetRequiredComponent(context, static architectureContext => architectureContext.GetService(), + "Service"); } /// @@ -39,7 +41,8 @@ public static class ContextAwareServiceExtensions { ArgumentNullException.ThrowIfNull(contextAware); var context = contextAware.GetContext(); - return context.GetSystem(); + return GetRequiredComponent(context, static architectureContext => architectureContext.GetSystem(), + "System"); } /// @@ -53,7 +56,8 @@ public static class ContextAwareServiceExtensions { ArgumentNullException.ThrowIfNull(contextAware); var context = contextAware.GetContext(); - return context.GetModel(); + return GetRequiredComponent(context, static architectureContext => architectureContext.GetModel(), + "Model"); } /// @@ -67,7 +71,8 @@ public static class ContextAwareServiceExtensions { ArgumentNullException.ThrowIfNull(contextAware); var context = contextAware.GetContext(); - return context.GetUtility(); + return GetRequiredComponent(context, static architectureContext => architectureContext.GetUtility(), + "Utility"); } #endregion @@ -194,5 +199,15 @@ public static class ContextAwareServiceExtensions return context.GetUtilitiesByPriority(); } + private static TComponent GetRequiredComponent(IArchitectureContext context, + Func resolver, string componentKind) + where TComponent : class + { + ArgumentNullException.ThrowIfNull(context); + + var component = resolver(context); + return component ?? throw new InvalidOperationException($"{componentKind} {typeof(TComponent)} not registered"); + } + #endregion } \ No newline at end of file