From ed269d4a348dab738367c04d1b1db8f60660752c Mon Sep 17 00:00:00 2001 From: gewuyou <95328647+GeWuYou@users.noreply.github.com> Date: Wed, 29 Apr 2026 08:16:05 +0800 Subject: [PATCH] =?UTF-8?q?test(cqrs):=20=E6=B8=85=E7=90=86=20Mediator=20?= =?UTF-8?q?=E6=9E=B6=E6=9E=84=E9=9B=86=E6=88=90=E6=B5=8B=E8=AF=95=E8=AD=A6?= =?UTF-8?q?=E5=91=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 优化 Mediator 架构集成测试的 helper 类型作用域,消除文件名与类型名警告 - 补充异步测试路径的 ConfigureAwait(false),满足 analyzer 要求 - 更新测试集合暴露类型为只读或抽象集合,保留行为不变 --- .../MediatorArchitectureIntegrationTests.cs | 581 +++++++++--------- 1 file changed, 291 insertions(+), 290 deletions(-) diff --git a/GFramework.Cqrs.Tests/Mediator/MediatorArchitectureIntegrationTests.cs b/GFramework.Cqrs.Tests/Mediator/MediatorArchitectureIntegrationTests.cs index 728f005a..b1ac1d24 100644 --- a/GFramework.Cqrs.Tests/Mediator/MediatorArchitectureIntegrationTests.cs +++ b/GFramework.Cqrs.Tests/Mediator/MediatorArchitectureIntegrationTests.cs @@ -62,7 +62,7 @@ public class MediatorArchitectureIntegrationTests TestContextAwareHandler.LastContext = _context; // 直接设置 var request = new TestContextAwareRequest(); - await _context!.SendRequestAsync(request); + await _context!.SendRequestAsync(request).ConfigureAwait(false); Assert.That(TestContextAwareHandler.LastContext, Is.Not.Null); Assert.That(TestContextAwareHandler.LastContext, Is.SameAs(_context)); @@ -74,7 +74,7 @@ public class MediatorArchitectureIntegrationTests TestServiceRetrievalHandler.LastRetrievedService = null; var request = new TestServiceRetrievalRequest(); - await _context!.SendRequestAsync(request); + await _context!.SendRequestAsync(request).ConfigureAwait(false); Assert.That(TestServiceRetrievalHandler.LastRetrievedService, Is.Not.Null); Assert.That(TestServiceRetrievalHandler.LastRetrievedService, Is.InstanceOf()); @@ -86,7 +86,7 @@ public class MediatorArchitectureIntegrationTests TestNestedRequestHandler2.ExecutionCount = 0; var request = new TestNestedRequest { Depth = 1 }; // 简化为深度1 - var result = await _context!.SendRequestAsync(request); + var result = await _context!.SendRequestAsync(request).ConfigureAwait(false); Assert.That(result, Is.EqualTo("Nested execution completed at depth 1")); Assert.That(TestNestedRequestHandler2.ExecutionCount, Is.EqualTo(1)); @@ -99,7 +99,7 @@ public class MediatorArchitectureIntegrationTests TestLifecycleHandler.DisposalCount = 0; var request = new TestLifecycleRequest(); - await _context!.SendRequestAsync(request); + await _context!.SendRequestAsync(request).ConfigureAwait(false); // 验证生命周期管理 Assert.That(TestLifecycleHandler.InitializationCount, Is.EqualTo(1)); @@ -116,14 +116,14 @@ public class MediatorArchitectureIntegrationTests .Select(async i => { var request = new TestScopedServiceRequest { RequestId = i }; - var result = await _context!.SendRequestAsync(request); + var result = await _context!.SendRequestAsync(request).ConfigureAwait(false); lock (results) { results.Add(result); } }); - await Task.WhenAll(tasks); + await Task.WhenAll(tasks).ConfigureAwait(false); // 验证每个请求都得到了独立的scope实例 Assert.That(results.Distinct().Count(), Is.EqualTo(10)); @@ -135,7 +135,7 @@ public class MediatorArchitectureIntegrationTests var request = new TestErrorPropagationRequest(); var ex = Assert.ThrowsAsync(async () => - await _context!.SendRequestAsync(request)); + await _context!.SendRequestAsync(request).ConfigureAwait(false)); Assert.That(ex!.Message, Is.EqualTo("Test error from handler")); Assert.That(ex.Data["RequestId"], Is.Not.Null); @@ -148,7 +148,7 @@ public class MediatorArchitectureIntegrationTests var request = new TestExceptionRequest(); Assert.ThrowsAsync(async () => - await _context!.SendRequestAsync(request)); + await _context!.SendRequestAsync(request).ConfigureAwait(false)); // 验证异常被捕获和记录 Assert.That(TestExceptionHandler.LastException, Is.Not.Null); @@ -164,7 +164,7 @@ public class MediatorArchitectureIntegrationTests for (int i = 0; i < iterations; i++) { var request = new TestPerformanceRequest2 { Id = i }; - var result = await _context!.SendRequestAsync(request); + var result = await _context!.SendRequestAsync(request).ConfigureAwait(false); Assert.That(result, Is.EqualTo(i)); } @@ -188,7 +188,7 @@ public class MediatorArchitectureIntegrationTests { var stopwatch = Stopwatch.StartNew(); var request = new TestUncachedRequest { Id = i }; - await _context!.SendRequestAsync(request); + await _context!.SendRequestAsync(request).ConfigureAwait(false); stopwatch.Stop(); uncachedTimes.Add(stopwatch.ElapsedMilliseconds); } @@ -198,7 +198,7 @@ public class MediatorArchitectureIntegrationTests { var stopwatch = Stopwatch.StartNew(); var request = new TestCachedRequest { Id = i }; - await _context!.SendRequestAsync(request); + await _context!.SendRequestAsync(request).ConfigureAwait(false); stopwatch.Stop(); cachedTimes.Add(stopwatch.ElapsedMilliseconds); } @@ -224,12 +224,12 @@ public class MediatorArchitectureIntegrationTests var task = Task.Run(async () => { var request = new TestConcurrentRequest { RequestId = requestId, OrderTracker = executionOrder }; - return await _context!.SendRequestAsync(request); + return await _context!.SendRequestAsync(request).ConfigureAwait(false); }); tasks.Add(task); } - var results = await Task.WhenAll(tasks); + var results = await Task.WhenAll(tasks).ConfigureAwait(false); // 验证所有请求都成功完成 Assert.That(results.Length, Is.EqualTo(concurrentRequests)); @@ -253,10 +253,10 @@ public class MediatorArchitectureIntegrationTests SharedState = sharedState, Increment = 1 }; - await _context!.SendRequestAsync(request); + await _context!.SendRequestAsync(request).ConfigureAwait(false); }); - await Task.WhenAll(tasks); + await Task.WhenAll(tasks).ConfigureAwait(false); // 验证最终状态正确(20个并发操作,每个+1) Assert.That(sharedState.Counter, Is.EqualTo(concurrentOperations)); @@ -269,7 +269,7 @@ public class MediatorArchitectureIntegrationTests TestIntegrationHandler.LastSystemCall = null; var request = new TestIntegrationRequest(); - var result = await _context!.SendRequestAsync(request); + var result = await _context!.SendRequestAsync(request).ConfigureAwait(false); Assert.That(result, Is.EqualTo("Integration successful")); Assert.That(TestIntegrationHandler.LastSystemCall, Is.EqualTo("System executed")); @@ -285,7 +285,7 @@ public class MediatorArchitectureIntegrationTests // 使用Mediator var mediatorRequest = new TestMediatorRequest { Value = 42 }; - var result = await _context.SendRequestAsync(mediatorRequest); + var result = await _context.SendRequestAsync(mediatorRequest).ConfigureAwait(false); Assert.That(result, Is.EqualTo(42)); // 验证两者可以共存 @@ -296,8 +296,8 @@ public class MediatorArchitectureIntegrationTests [Test] public async Task ContextAware_Handler_Should_Use_A_Fresh_Instance_Per_Request() { - var firstResult = await _context!.SendRequestAsync(new TestPerDispatchContextAwareRequest()); - var secondResult = await _context.SendRequestAsync(new TestPerDispatchContextAwareRequest()); + var firstResult = await _context!.SendRequestAsync(new TestPerDispatchContextAwareRequest()).ConfigureAwait(false); + var secondResult = await _context.SendRequestAsync(new TestPerDispatchContextAwareRequest()).ConfigureAwait(false); Assert.Multiple(() => { @@ -306,312 +306,313 @@ public class MediatorArchitectureIntegrationTests Assert.That(TestPerDispatchContextAwareHandler.Contexts, Has.All.SameAs(_context)); }); } -} + #region Integration Test Classes -#region Integration Test Classes - -public sealed class TestContextAwareRequestHandler : IRequestHandler -{ - public ValueTask Handle(TestContextAwareRequest request, CancellationToken cancellationToken) + public sealed class TestContextAwareRequestHandler : IRequestHandler { - // 保持测试中设置的上下文,不要重置为null - return new ValueTask("Context accessed"); - } -} - -public sealed class TestServiceRetrievalRequestHandler : IRequestHandler -{ - public ValueTask Handle(TestServiceRetrievalRequest request, CancellationToken cancellationToken) - { - TestServiceRetrievalHandler.LastRetrievedService = new TestService(); - return new ValueTask("Service retrieved"); - } -} - -public sealed class TestNestedRequestHandler : IRequestHandler -{ - public ValueTask Handle(TestNestedRequest request, CancellationToken cancellationToken) - { - TestNestedRequestHandler2.ExecutionCount++; - - if (request.Depth >= 1) // 简化条件 + public ValueTask Handle(TestContextAwareRequest request, CancellationToken cancellationToken) { - // 模拟嵌套调用 + // 保持测试中设置的上下文,不要重置为null + return new ValueTask("Context accessed"); + } + } + + public sealed class TestServiceRetrievalRequestHandler : IRequestHandler + { + public ValueTask Handle(TestServiceRetrievalRequest request, CancellationToken cancellationToken) + { + TestServiceRetrievalHandler.LastRetrievedService = new TestService(); + return new ValueTask("Service retrieved"); + } + } + + public sealed class TestNestedRequestHandler : IRequestHandler + { + public ValueTask Handle(TestNestedRequest request, CancellationToken cancellationToken) + { + TestNestedRequestHandler2.ExecutionCount++; + + if (request.Depth >= 1) // 简化条件 + { + // 模拟嵌套调用 + return new ValueTask($"Nested execution completed at depth {request.Depth}"); + } + return new ValueTask($"Nested execution completed at depth {request.Depth}"); } - - return new ValueTask($"Nested execution completed at depth {request.Depth}"); } -} -public sealed class TestLifecycleRequestHandler : IRequestHandler -{ - public ValueTask Handle(TestLifecycleRequest request, CancellationToken cancellationToken) + public sealed class TestLifecycleRequestHandler : IRequestHandler { - TestLifecycleHandler.InitializationCount++; - // 模拟一些工作 - TestLifecycleHandler.DisposalCount++; - return new ValueTask("Lifecycle managed"); - } -} - -public sealed class TestScopedServiceRequestHandler : IRequestHandler -{ - public ValueTask Handle(TestScopedServiceRequest request, CancellationToken cancellationToken) - { - // 模拟返回请求ID - return new ValueTask(request.RequestId); - } -} - -public sealed class TestErrorPropagationRequestHandler : IRequestHandler -{ - public ValueTask Handle(TestErrorPropagationRequest request, CancellationToken cancellationToken) - { - var ex = new InvalidOperationException("Test error from handler"); - ex.Data["RequestId"] = Guid.NewGuid(); - throw ex; - } -} - -public sealed class TestExceptionRequestHandler : IRequestHandler -{ - public ValueTask Handle(TestExceptionRequest request, CancellationToken cancellationToken) - { - TestExceptionHandler.LastException = new DivideByZeroException("Test exception"); - throw TestExceptionHandler.LastException; - } -} - -public sealed class TestPerformanceRequest2Handler : IRequestHandler -{ - public ValueTask Handle(TestPerformanceRequest2 request, CancellationToken cancellationToken) - { - return new ValueTask(request.Id); - } -} - -public sealed class TestUncachedRequestHandler : IRequestHandler -{ - public ValueTask Handle(TestUncachedRequest request, CancellationToken cancellationToken) - { - // 模拟一些处理时间 - Task.Delay(5, cancellationToken).Wait(cancellationToken); - return new ValueTask(request.Id); - } -} - -public sealed class TestCachedRequestHandler : IRequestHandler -{ - private static readonly Dictionary _cache = new(); - - public ValueTask Handle(TestCachedRequest request, CancellationToken cancellationToken) - { - if (_cache.TryGetValue(request.Id, out var cachedValue)) + public ValueTask Handle(TestLifecycleRequest request, CancellationToken cancellationToken) { - return new ValueTask(cachedValue); + TestLifecycleHandler.InitializationCount++; + // 模拟一些工作 + TestLifecycleHandler.DisposalCount++; + return new ValueTask("Lifecycle managed"); } - - // 模拟处理时间 - Task.Delay(10, cancellationToken).Wait(cancellationToken); - var newValue = request.Id; - _cache[request.Id] = newValue; - return new ValueTask(newValue); } -} -public sealed class TestConcurrentRequestHandler : IRequestHandler -{ - public ValueTask Handle(TestConcurrentRequest request, CancellationToken cancellationToken) + public sealed class TestScopedServiceRequestHandler : IRequestHandler { - lock (request.OrderTracker) + public ValueTask Handle(TestScopedServiceRequest request, CancellationToken cancellationToken) { - request.OrderTracker.Add(request.RequestId); + // 模拟返回请求ID + return new ValueTask(request.RequestId); } - - return new ValueTask(request.RequestId); } -} -public sealed class TestStateModificationRequestHandler : IRequestHandler -{ - public ValueTask Handle(TestStateModificationRequest request, CancellationToken cancellationToken) + public sealed class TestErrorPropagationRequestHandler : IRequestHandler { - request.SharedState.Counter += request.Increment; - return new ValueTask("State modified"); + public ValueTask Handle(TestErrorPropagationRequest request, CancellationToken cancellationToken) + { + var ex = new InvalidOperationException("Test error from handler"); + ex.Data["RequestId"] = Guid.NewGuid(); + throw ex; + } } -} -public sealed class TestIntegrationRequestHandler : IRequestHandler -{ - public ValueTask Handle(TestIntegrationRequest request, CancellationToken cancellationToken) + public sealed class TestExceptionRequestHandler : IRequestHandler { - TestIntegrationHandler.LastSystemCall = "System executed"; - return new ValueTask("Integration successful"); + public ValueTask Handle(TestExceptionRequest request, CancellationToken cancellationToken) + { + TestExceptionHandler.LastException = new DivideByZeroException("Test exception"); + throw TestExceptionHandler.LastException; + } } -} -public sealed class TestMediatorRequestHandler : IRequestHandler -{ - public ValueTask Handle(TestMediatorRequest request, CancellationToken cancellationToken) + public sealed class TestPerformanceRequest2Handler : IRequestHandler { - return new ValueTask(request.Value); + public ValueTask Handle(TestPerformanceRequest2 request, CancellationToken cancellationToken) + { + return new ValueTask(request.Id); + } } -} -/// -/// 用于验证自动扫描到的上下文感知处理器会按请求创建新实例。 -/// -public sealed class TestPerDispatchContextAwareHandler : ContextAwareBase, - IRequestHandler -{ - private static int _nextInstanceId; - private readonly int _instanceId = Interlocked.Increment(ref _nextInstanceId); - - public static List Contexts { get; } = []; - public static List SeenInstanceIds { get; } = []; - - /// - /// 记录当前实例编号与收到的架构上下文。 - /// - /// 请求实例。 - /// 取消令牌。 - /// 当前处理器实例编号。 - public ValueTask Handle(TestPerDispatchContextAwareRequest request, CancellationToken cancellationToken) + public sealed class TestUncachedRequestHandler : IRequestHandler { - Contexts.Add(Context); - SeenInstanceIds.Add(_instanceId); - return ValueTask.FromResult(_instanceId); + public ValueTask Handle(TestUncachedRequest request, CancellationToken cancellationToken) + { + // 模拟一些处理时间 + Task.Delay(5, cancellationToken).Wait(cancellationToken); + return new ValueTask(request.Id); + } + } + + public sealed class TestCachedRequestHandler : IRequestHandler + { + private static readonly Dictionary _cache = new(); + + public ValueTask Handle(TestCachedRequest request, CancellationToken cancellationToken) + { + if (_cache.TryGetValue(request.Id, out var cachedValue)) + { + return new ValueTask(cachedValue); + } + + // 模拟处理时间 + Task.Delay(10, cancellationToken).Wait(cancellationToken); + var newValue = request.Id; + _cache[request.Id] = newValue; + return new ValueTask(newValue); + } + } + + public sealed class TestConcurrentRequestHandler : IRequestHandler + { + public ValueTask Handle(TestConcurrentRequest request, CancellationToken cancellationToken) + { + lock (request.OrderTracker) + { + request.OrderTracker.Add(request.RequestId); + } + + return new ValueTask(request.RequestId); + } + } + + public sealed class TestStateModificationRequestHandler : IRequestHandler + { + public ValueTask Handle(TestStateModificationRequest request, CancellationToken cancellationToken) + { + request.SharedState.Counter += request.Increment; + return new ValueTask("State modified"); + } + } + + public sealed class TestIntegrationRequestHandler : IRequestHandler + { + public ValueTask Handle(TestIntegrationRequest request, CancellationToken cancellationToken) + { + TestIntegrationHandler.LastSystemCall = "System executed"; + return new ValueTask("Integration successful"); + } + } + + public sealed class TestMediatorRequestHandler : IRequestHandler + { + public ValueTask Handle(TestMediatorRequest request, CancellationToken cancellationToken) + { + return new ValueTask(request.Value); + } } /// - /// 重置跨测试共享的实例跟踪状态。 + /// 用于验证自动扫描到的上下文感知处理器会按请求创建新实例。 /// - public static void Reset() + public sealed class TestPerDispatchContextAwareHandler : ContextAwareBase, + IRequestHandler { - Contexts.Clear(); - SeenInstanceIds.Clear(); - _nextInstanceId = 0; - } -} + private static int _nextInstanceId; + private static readonly List TrackedContexts = []; + private static readonly List TrackedInstanceIds = []; + private readonly int _instanceId = Interlocked.Increment(ref _nextInstanceId); -public sealed record TestContextAwareRequest : IRequest; + public static IReadOnlyList Contexts => TrackedContexts; + public static IReadOnlyList SeenInstanceIds => TrackedInstanceIds; -public static class TestContextAwareHandler -{ - public static IArchitectureContext? LastContext { get; set; } -} + /// + /// 记录当前实例编号与收到的架构上下文。 + /// + /// 请求实例。 + /// 取消令牌。 + /// 当前处理器实例编号。 + public ValueTask Handle(TestPerDispatchContextAwareRequest request, CancellationToken cancellationToken) + { + TrackedContexts.Add(Context); + TrackedInstanceIds.Add(_instanceId); + return ValueTask.FromResult(_instanceId); + } -public sealed record TestServiceRetrievalRequest : IRequest; - -public static class TestServiceRetrievalHandler -{ - public static object? LastRetrievedService { get; set; } -} - -public class TestService -{ - public string Id { get; } = Guid.NewGuid().ToString(); -} - -public sealed record TestNestedRequest : IRequest -{ - public int Depth { get; init; } -} - -public static class TestNestedRequestHandler2 -{ - public static int ExecutionCount { get; set; } -} - -// 生命周期相关类 -public sealed record TestLifecycleRequest : IRequest; - -public static class TestLifecycleHandler -{ - public static int InitializationCount { get; set; } - public static int DisposalCount { get; set; } -} - -public sealed record TestScopedServiceRequest : IRequest -{ - public int RequestId { get; init; } -} - -// 错误处理相关类 -public sealed record TestErrorPropagationRequest : IRequest; - -public static class TestExceptionHandler -{ - public static Exception? LastException { get; set; } -} - -public sealed record TestExceptionRequest : IRequest; - -// 性能测试相关类 -public sealed record TestPerformanceRequest2 : IRequest -{ - public int Id { get; init; } -} - -public sealed record TestUncachedRequest : IRequest -{ - public int Id { get; init; } -} - -public sealed record TestCachedRequest : IRequest -{ - public int Id { get; init; } -} - -// 并发测试相关类 -public class SharedState -{ - public int Counter { get; set; } -} - -public sealed record TestConcurrentRequest : IRequest -{ - public int RequestId { get; init; } - public List OrderTracker { get; init; } = new(); -} - -public sealed record TestStateModificationRequest : IRequest -{ - public SharedState SharedState { get; init; } = null!; - public int Increment { get; init; } -} - -// 集成测试相关类 -public static class TestIntegrationHandler -{ - public static string? LastSystemCall { get; set; } -} - -public sealed record TestIntegrationRequest : IRequest; - -public sealed record TestMediatorRequest : IRequest -{ - public int Value { get; init; } -} - -/// -/// 用于验证每次请求分发都会获得新的上下文感知处理器实例。 -/// -public sealed record TestPerDispatchContextAwareRequest : IRequest; - -// 传统命令用于混合测试 -public class TestTraditionalCommand : ICommand -{ - public bool Executed { get; private set; } - - public void Execute() => Executed = true; - - public void SetContext(IArchitectureContext context) - { + /// + /// 重置跨测试共享的实例跟踪状态。 + /// + public static void Reset() + { + TrackedContexts.Clear(); + TrackedInstanceIds.Clear(); + _nextInstanceId = 0; + } } - public IArchitectureContext GetContext() => null!; -} + public sealed record TestContextAwareRequest : IRequest; -#endregion + public static class TestContextAwareHandler + { + public static IArchitectureContext? LastContext { get; set; } + } + + public sealed record TestServiceRetrievalRequest : IRequest; + + public static class TestServiceRetrievalHandler + { + public static object? LastRetrievedService { get; set; } + } + + public class TestService + { + public string Id { get; } = Guid.NewGuid().ToString(); + } + + public sealed record TestNestedRequest : IRequest + { + public int Depth { get; init; } + } + + public static class TestNestedRequestHandler2 + { + public static int ExecutionCount { get; set; } + } + + // 生命周期相关类 + public sealed record TestLifecycleRequest : IRequest; + + public static class TestLifecycleHandler + { + public static int InitializationCount { get; set; } + public static int DisposalCount { get; set; } + } + + public sealed record TestScopedServiceRequest : IRequest + { + public int RequestId { get; init; } + } + + // 错误处理相关类 + public sealed record TestErrorPropagationRequest : IRequest; + + public static class TestExceptionHandler + { + public static Exception? LastException { get; set; } + } + + public sealed record TestExceptionRequest : IRequest; + + // 性能测试相关类 + public sealed record TestPerformanceRequest2 : IRequest + { + public int Id { get; init; } + } + + public sealed record TestUncachedRequest : IRequest + { + public int Id { get; init; } + } + + public sealed record TestCachedRequest : IRequest + { + public int Id { get; init; } + } + + // 并发测试相关类 + public class SharedState + { + public int Counter { get; set; } + } + + public sealed record TestConcurrentRequest : IRequest + { + public int RequestId { get; init; } + public ICollection OrderTracker { get; init; } = new List(); + } + + public sealed record TestStateModificationRequest : IRequest + { + public SharedState SharedState { get; init; } = null!; + public int Increment { get; init; } + } + + // 集成测试相关类 + public static class TestIntegrationHandler + { + public static string? LastSystemCall { get; set; } + } + + public sealed record TestIntegrationRequest : IRequest; + + public sealed record TestMediatorRequest : IRequest + { + public int Value { get; init; } + } + + /// + /// 用于验证每次请求分发都会获得新的上下文感知处理器实例。 + /// + public sealed record TestPerDispatchContextAwareRequest : IRequest; + + // 传统命令用于混合测试 + public class TestTraditionalCommand : ICommand + { + public bool Executed { get; private set; } + + public void Execute() => Executed = true; + + public void SetContext(IArchitectureContext context) + { + } + + public IArchitectureContext GetContext() => null!; + } + + #endregion +}