首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何在没有响应的情况下对MassTransit使用者进行单元测试

如何在没有响应的情况下对MassTransit使用者进行单元测试
EN

Stack Overflow用户
提问于 2022-06-09 16:30:35
回答 2查看 938关注 0票数 2

我想对我的MassTransit使用者进行单元测试,它不返回响应。目前,我的测试似乎发布了一条消息,但消费者没有被触发,所以我的断点根本没有被击中。

消费者是相当直截了当的,但它确实有通过DI注入的服务。

代码语言:javascript
运行
复制
public class BudgetExceededConsumer : IConsumer<IBudgetExceeded>
{
    private readonly INotificationHubService _notificationHubService;

    public BudgetExceededConsumer(INotificationHubService notificationHubService)
    {
        _notificationHubService = notificationHubService;
    }

    public async Task Consume(ConsumeContext<IBudgetExceeded> context)
    {
        try
        {
            var message = context.Message;

            await _notificationHubService.SendNotificationAsync(context.Message);
        }
        catch (Exception ex)
        {
            throw new Exception("Failed to send push notification for exceeding budget usage", ex);
        }
    }
}

使用以下方法将使用者添加到my函数中:

代码语言:javascript
运行
复制
        builder.Services.AddMassTransitForAzureFunctions(cfg =>
        {
            cfg.AddConsumersFromNamespaceContaining<ConsumerNamespace>();

        });

我有一个相对简单的服务,其他函数使用它来发送消息:

代码语言:javascript
运行
复制
    private readonly ISendEndpointProvider _sendEndpoint;

    public MessagingService(ISendEndpointProvider sendEndpoint)
    {
        _sendEndpoint = sendEndpoint;
    }

    public async Task SendMessage<T>(string queueName, object messageBody) where T : class, MessageBase
    {
        var endpoint = await _sendEndpoint.GetSendEndpoint(new Uri($"queue:{queueName}"));

        await endpoint.Send<T>(messageBody);
    }

我想为使用者编写一个简单的测试,这样我就可以模拟服务,然后验证模拟的服务是否被调用了。然而,我无法达到运行测试和我的消费者被断点击中的地步。我不会设置注入到DI中任何地方的使用者的服务。目前,这并不是抱怨,这让我觉得我错过了一些设置。

代码语言:javascript
运行
复制
    public async Task Budget_message_gets_consumed()
    {
        await using var provider = new ServiceCollection()
            .AddMassTransitInMemoryTestHarness(cfg =>
            {
                cfg.AddConsumer<BudgetExceededConsumer>();
                cfg.AddConsumerTestHarness<BudgetExceededConsumer>();
            })
            .BuildServiceProvider(true);

        var harness = provider.GetRequiredService<InMemoryTestHarness>();

        await harness.Start();

        try
        {
            var bus = provider.GetRequiredService<IBus>();

            BudgetExceededMessage message = new BudgetExceededMessage
            {
                UserEmailAddress = "test@email.com",
                Budget = "£20.00",
                TotalSpend = "£23.56"
            };
            await bus.Publish(message);

            var result = await harness.Consumed.Any<IBudgetExceeded>();

            Assert.That(result, Is.True); //This is true
            
            var consumerHarness = provider.GetRequiredService<IConsumerTestHarness<BudgetExceededConsumer>>();
            var result2 = await consumerHarness.Consumed.Any<IBudgetExceeded>();
            Assert.That(result2, Is.True); //This is FALSE. 
        }
        finally
        {
            await harness.Stop();

            await provider.DisposeAsync();
        }
    }

如您所见,第二个断言是假的。我想,如果这是真的,我会看到我的消费者的断点受到打击。

这里是否存在需要更改的设置,以便正确评估第二个断言?我知道我的设置与文档略有不同,因为我没有使用给出响应的方法。

谢谢

EN

Stack Overflow用户

发布于 2022-07-07 12:25:21

我或多或少地遇到了同样的问题,并最终使它在两个更改(第二个更改可选)中正确工作。

1.我的使用者使用的是一个指定的端点,所以我需要在线束中的使用者设置中配置这个端点。

要检查这是否是您的问题,您可以查看日志(注意第3行和第5行)。

代码语言:javascript
运行
复制
08:00:18.424-D Starting bus: loopback://localhost/
08:00:18.440-D Endpoint Ready: loopback://localhost/mbp14_testhost_bus_gtwyyyrqpojbqfzhbdpgyrnng6
08:00:18.440-D Endpoint Ready: loopback://localhost/PublishPdp
08:00:18.442-I Bus started: loopback://localhost/
08:00:18.454-D Create send transport: loopback://localhost/publish-pdp?bind=true
08:00:18.507-D SEND loopback://localhost/publish-pdp?bind=true 34680000-8e6c-1217-6974-08da601042eb Ownit.Next.Common.Messages.PublishPdp

注意两个不同的地址:PublishPdppublish-pdp。在测试工具中,添加以下代码:

代码语言:javascript
运行
复制
EndpointConvention.Map<PublishPdp>(new Uri("queue:publish-pdp"));

还不够,我还必须更新使用者配置:

代码语言:javascript
运行
复制
await using var provider = new ServiceCollection()
    .AddMassTransitTestHarness(cfg =>
    {
        cfg.AddConsumer<PublishPdpConsumer>()
           .Endpoint(e => e.Name = "publish-pdp"); // Explicitly set the name.
    })
    .AddScoped(x => Log.Logger)
    .BuildServiceProvider(true);

或者使用默认命名:

代码语言:javascript
运行
复制
// This also works by using the default naming scheme
EndpointConvention.Map<PublishPdp>(new Uri("queue:PublishPdp"));

await using var provider = new ServiceCollection()
    .AddMassTransitTestHarness(cfg =>
    {
        cfg.AddConsumer<PublishPdpConsumer>(); // No naming needed
    })
    .AddScoped(x => Log.Logger)
    .BuildServiceProvider(true);

我曾假设静态EndpointConvention.Map<>()也会影响消费者,但事实并非如此。使用者甚至有一个静态抑制器,它显式地设置了这一点。

当您不使用默认名称时,测试用例必须具有显式的EndpointConvention.Map<>(new Url("queue:X")) AddConsumer<>().Endpoint(e => e.Name = "X")。在测试工具中使用Send时,仍然需要使用EndpointConvention.Map<>(new Url("queue:X")),其中X是消息类型的名称。

AddConsumerTestHarness 2.显式添加似乎没有必要的

有一些混淆,因为文档只显示两个示例,GitHub问题上可用的大多数示例都显示了“旧”样式的设置。

这个方法有一个ObsoleteAttribute

代码语言:javascript
运行
复制
Consider migrating to AddMassTransitTestHarness, which does not require this extra configuration

实际上,它似乎没有必要,测试用例可以这样编写:

代码语言:javascript
运行
复制
[Fact]
public async Task Publish_Pdp_Is_Consumed_With_DI()
{
    // This mapping is needed in the test
    EndpointConvention.Map<PublishPdp>(new Uri("queue:publish-pdp"));

    await using var provider = new ServiceCollection()
        .AddMassTransitTestHarness(cfg =>
        {
            // Need to explicitly name the endpoint.  Commenting out one
            // or both causes the test to fail.
            cfg.AddConsumer<PublishPdpConsumer>()
               .Endpoint(e => e.Name = "publish-pdp");
        })
        .AddScoped(x => Log.Logger)  // I inject Serilog so I need this.
        .BuildServiceProvider(true);

    var harness = provider.GetRequiredService<ITestHarness>();

    await harness.Start();

    await harness.Bus.Send<PublishPdp>(new
    {
        Id = Guid.NewGuid(),
        CreatedBy = "test_user"
    });

    Assert.True(await harness.Sent.Any<PublishPdp>());
    Assert.True(await harness.Consumed.Any<PublishPdp>());
}

代码语言:javascript
运行
复制
[Fact]
public async Task Publish_Pdp_Is_Consumed_With_DI()
{
    // Map the default name
    EndpointConvention.Map<PublishPdp>(new Uri("queue:PublishPdp"));

    await using var provider = new ServiceCollection()
        .AddMassTransitTestHarness(cfg =>
        {
            // Don't name the endpoint, but explicitly map the default
            cfg.AddConsumer<PublishPdpConsumer>();
        })
        .AddScoped(x => Log.Logger)  // I inject Serilog so I need this.
        .BuildServiceProvider(true);

    var harness = provider.GetRequiredService<ITestHarness>();

    await harness.Start();

    await harness.Bus.Send<PublishPdp>(new
    {
        Id = Guid.NewGuid(),
        CreatedBy = "test_user"
    });

    Assert.True(await harness.Sent.Any<PublishPdp>());
    Assert.True(await harness.Consumed.Any<PublishPdp>());
}

感谢克里斯的帮助。

票数 0
EN
查看全部 2 条回答
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/72563757

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档