首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何在使用IPublishEndpoint时注入InMemoryTestHarness

如何在使用IPublishEndpoint时注入InMemoryTestHarness
EN

Stack Overflow用户
提问于 2021-10-02 12:47:05
回答 2查看 1.3K关注 0票数 0

概述

所以我有一个现有的web,它使用MediatR命令。我正致力于将MT集成到其中一些中,以便为各种目的向RMQ发布消息。我能够很好地将它集成到我的命令中,但是在集成测试期间,我在用InMemoryHarness进行测试时遇到了问题。

详细信息

我有一个NUnit测试夹具,它可以像医生们描述的那样设置内存管理。

代码语言:javascript
运行
复制
[OneTimeSetUp]
public async Task RunBeforeAnyTests()
{
    var dockerDbPort = await DockerDatabaseUtilities.EnsureDockerStartedAndGetPortPortAsync();
    var dockerConnectionString = DockerDatabaseUtilities.GetSqlConnectionString(dockerDbPort.ToString());

    var builder = new ConfigurationBuilder()
        .SetBasePath(Directory.GetCurrentDirectory())
        .AddEnvironmentVariables();

    _configuration = builder.Build();

    var services = new ServiceCollection();

    // various other registration

    // MassTransit Setup -- Do Not Delete Comment
    _provider = services.AddMassTransitInMemoryTestHarness(cfg =>
    {
        // Consumers here
    }).BuildServiceProvider(true);
    _harness = _provider.GetRequiredService<InMemoryTestHarness>();
            
    await _harness.Start();
}

我还有一个MediatR处理程序,它看起来可能如下所示:

代码语言:javascript
运行
复制
public class Handler : IRequestHandler<AddRecipeCommand, RecipeDto>
{
    private readonly RecipesDbContext _db;
    private readonly IMapper _mapper;
    private readonly IPublishEndpoint _publishEndpoint;

    public Handler(RecipesDbContext db, IMapper mapper, IPublishEndpoint publishEndpoint)
    {
        _mapper = mapper;
        _publishEndpoint = publishEndpoint;
        _db = db;
    }

    public async Task<RecipeDto> Handle(AddRecipeCommand request, CancellationToken cancellationToken)
    {
        var recipe = _mapper.Map<Recipe> (request.RecipeToAdd);
        _db.Recipes.Add(recipe);

        await _publishEndpoint.Publish<IRecipeAdded>(new
        {
            RecipeId = recipe.Id
        });

        await _db.SaveChangesAsync();

        return await _db.Recipes
            .ProjectTo<RecipeDto>(_mapper.ConfigurationProvider)
            .FirstOrDefaultAsync(r => r.Id == recipe.Id);
    }
}

我有一个像这样的测试,在注射IPublishEndpoint之前就通过了

代码语言:javascript
运行
复制
[Test]
public async Task can_add_new_recipe_to_db()
{
    // Arrange
    var fakeRecipeOne = new FakeRecipeForCreationDto { }.Generate();

    // Act
    var command = new AddRecipe.AddRecipeCommand(fakeRecipeOne);
    var recipeReturned = await SendAsync(command);
    var recipeCreated = await ExecuteDbContextAsync(db => db.Recipes.SingleOrDefaultAsync());

    // Assert
    recipeReturned.Should().BeEquivalentTo(fakeRecipeOne, options =>
        options.ExcludingMissingMembers());
    recipeCreated.Should().BeEquivalentTo(fakeRecipeOne, options =>
        options.ExcludingMissingMembers());
}

但是,当MediatR命令包括MT发布时,测试失败:

代码语言:javascript
运行
复制
 ----> System.InvalidOperationException : Unable to resolve service for type 'MassTransit.IPublishEndpoint' while attempting to activate 'RecipeManagement.Domain.Recipes.Features.AddRecipe+Handler'.

我在哪里

同样,这个MediatR命令在针对RMQ运行实际应用程序时运行良好,但是内存管理似乎没有引入总线来正确注入IPublishEndpoint

我试过把这样的东西带来不同的口味,但都没有用。

代码语言:javascript
运行
复制
var bus = _provider.GetRequiredService<IBus>();
services.AddSingleton<IPublishEndpoint>(bus);

我想我可以使用一个带有RMQ的坞容器,并将它用于我的测试,但是如果我能够使用内存中的工具来实现性能和简单性,那就太好了。

对于我该如何处理这件事,有什么想法吗?

EN

Stack Overflow用户

回答已采纳

发布于 2021-10-05 03:29:15

已更新

因此,下面的方法会起作用,但它不会让您从发布的角度测试任何针对工具的测试,这显然不是理想的,如果您像这样设置注册,它现在应该会飞起来:

代码语言:javascript
运行
复制
        services.AddMassTransitInMemoryTestHarness(cfg =>
        {
            // Consumer Registration -- Do Not Delete Comment

            cfg.AddConsumer<AddToBook>();
            cfg.AddConsumerTestHarness<AddToBook>();
        });
        
        _provider = services.BuildServiceProvider();
        _scopeFactory = _provider.GetService<IServiceScopeFactory>();
        
        _harness = _provider.GetRequiredService<InMemoryTestHarness>();
        await _harness.Start();

年长的

因此,内存中的db似乎没有办法尽可能地为消费者注册IPublishEndpoint

代码语言:javascript
运行
复制
_provider = services.AddMassTransitInMemoryTestHarness(cfg =>
   {
      cfg.AddConsumer<AddToBook>();
      cfg.AddConsumerTestHarness<AddToBook>();
   }).BuildServiceProvider();
_harness = _provider.GetRequiredService<InMemoryTestHarness>();

但我所能做的只是使用Moq来添加一个模拟。我不需要在这个级别测试发布后会发生什么,因为这是一个进程外操作,所以这样做可以完成注册工作,从而使我的DI高兴。

代码语言:javascript
运行
复制
services.AddScoped(_ => Mock.Of<IPublishEndpoint>());
票数 1
EN
查看全部 2 条回答
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/69417049

复制
相关文章

相似问题

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