From 337ffbd5808e39099aab613573937e88f40950d6 Mon Sep 17 00:00:00 2001
From: gewuyou <95328647+GeWuYou@users.noreply.github.com>
Date: Mon, 11 May 2026 12:37:55 +0800
Subject: [PATCH] =?UTF-8?q?test(cqrs):=20=E8=A1=A5=E9=BD=90=E9=80=9A?=
=?UTF-8?q?=E7=9F=A5=E5=8F=91=E5=B8=83=E5=99=A8=E8=A7=A3=E6=9E=90=E7=BC=93?=
=?UTF-8?q?=E5=AD=98=E5=9B=9E=E5=BD=92=E6=B5=8B=E8=AF=95?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 新增 notification publisher 多实例冲突时抛错的回归测试
- 补充首次解析后复用同一 publisher 且不重复查容器的缓存测试
- 更新测试发布器计数以验证缓存命中的发布调用次数
---
.../Cqrs/CqrsNotificationPublisherTests.cs | 70 +++++++++++++++++++
1 file changed, 70 insertions(+)
diff --git a/GFramework.Cqrs.Tests/Cqrs/CqrsNotificationPublisherTests.cs b/GFramework.Cqrs.Tests/Cqrs/CqrsNotificationPublisherTests.cs
index d862652d..485c11e7 100644
--- a/GFramework.Cqrs.Tests/Cqrs/CqrsNotificationPublisherTests.cs
+++ b/GFramework.Cqrs.Tests/Cqrs/CqrsNotificationPublisherTests.cs
@@ -91,6 +91,70 @@ internal sealed class CqrsNotificationPublisherTests
Assert.That(handler.ObservedContext, Is.SameAs(architectureContext.Object));
}
+ ///
+ /// 验证当容器里可见多个通知发布策略时,dispatcher 会拒绝在歧义状态下继续发布。
+ ///
+ [Test]
+ public void PublishAsync_Should_Throw_When_Multiple_NotificationPublishers_Are_Registered()
+ {
+ var runtime = CreateRuntime(
+ container =>
+ {
+ container
+ .Setup(currentContainer => currentContainer.GetAll(typeof(INotificationHandler)))
+ .Returns([new RecordingNotificationHandler("only", [])]);
+ container
+ .Setup(currentContainer => currentContainer.GetAll(typeof(INotificationPublisher)))
+ .Returns(
+ [
+ new TrackingNotificationPublisher(),
+ new TrackingNotificationPublisher()
+ ]);
+ });
+
+ Assert.That(
+ async () => await runtime.PublishAsync(new FakeCqrsContext(), new PublisherNotification()).ConfigureAwait(false),
+ Throws.InvalidOperationException.With.Message.EqualTo(
+ $"Multiple {typeof(INotificationPublisher).FullName} instances are registered. Remove duplicate notification publisher strategies before publishing notifications."));
+ }
+
+ ///
+ /// 验证 dispatcher 在首次发布时解析通知发布器后,会复用同一实例并停止继续查询容器。
+ ///
+ [Test]
+ public async Task PublishAsync_Should_Cache_Resolved_NotificationPublisher_After_First_Publish()
+ {
+ var firstPublisher = new TrackingNotificationPublisher();
+ var secondPublisher = new TrackingNotificationPublisher();
+ var notificationPublisherLookupCount = 0;
+ var runtime = CreateRuntime(
+ container =>
+ {
+ container
+ .Setup(currentContainer => currentContainer.GetAll(typeof(INotificationHandler)))
+ .Returns([new RecordingNotificationHandler("only", [])]);
+ container
+ .Setup(currentContainer => currentContainer.GetAll(typeof(INotificationPublisher)))
+ .Returns(() =>
+ {
+ notificationPublisherLookupCount++;
+ return notificationPublisherLookupCount switch
+ {
+ 1 => [firstPublisher],
+ 2 => [secondPublisher],
+ _ => throw new AssertionException("Notification publisher should be resolved at most once.")
+ };
+ });
+ });
+
+ await runtime.PublishAsync(new FakeCqrsContext(), new PublisherNotification()).ConfigureAwait(false);
+ await runtime.PublishAsync(new FakeCqrsContext(), new PublisherNotification()).ConfigureAwait(false);
+
+ Assert.That(notificationPublisherLookupCount, Is.EqualTo(1));
+ Assert.That(firstPublisher.PublishCallCount, Is.EqualTo(2));
+ Assert.That(secondPublisher.PublishCallCount, Is.Zero);
+ }
+
///
/// 验证内置 `TaskWhenAll` 发布器会继续调度所有处理器,而不是沿用默认顺序发布器的失败即停语义。
///
@@ -262,6 +326,11 @@ internal sealed class CqrsNotificationPublisherTests
///
public bool WasCalled { get; private set; }
+ ///
+ /// 获取当前发布器累计执行发布的次数。
+ ///
+ public int PublishCallCount { get; private set; }
+
///
/// 记录当前发布器已被调用,并继续按当前顺序执行所有处理器。
///
@@ -275,6 +344,7 @@ internal sealed class CqrsNotificationPublisherTests
where TNotification : INotification
{
WasCalled = true;
+ PublishCallCount++;
foreach (var handler in context.Handlers)
{