ASP.NET核心Web API中的单元测试RabbitMQ消息生成器

pb3s4cty  于 2023-03-02  发布在  RabbitMQ
关注(0)|答案(1)|浏览(156)

我已经按照RabbitMQ文档(https://www.rabbitmq.com/tutorials/tutorial-seven-dotnet.html)提供的教程设置了一个MessageProducer,发布者确认。
我使用XUnit和NSubstitute进行测试,现在我正在努力对为IModel _channel定义的回调函数的功能进行单元测试。
如果我只是测试通道是否收到了预期数量的BasicPublish(),则测试将运行到完成。
以下是我的服务方式:

public async Task SendMessagesWithConfirmAsync<T>(IEnumerable<T> messages, string queueName, string routingKey)
{
    _channel.QueueDeclare(queueName, true, false);

    _channel.ConfirmSelect();

    // Register callbacks to handle acknowledgments
    _channel.BasicAcks += (sender, ea) => CleanOutstandingConfirms(ea.DeliveryTag, ea.Multiple);

    _channel.BasicNacks += (sender, ea) =>
        {
            _outstandingConfirms.TryGetValue(ea.DeliveryTag, out var body);

            Console.WriteLine(
                $"Message with body {body} has been nack-ed. Sequence number: {ea.DeliveryTag}, multiple: {ea.Multiple}");

            CleanOutstandingConfirms(ea.DeliveryTag, ea.Multiple);
    };

    foreach (var message in messages)
    {
        var body = JsonSerializer.Serialize(message);
        _outstandingConfirms.TryAdd(_channel.NextPublishSeqNo, body);
        _channel.BasicPublish(queueName, routingKey, null, Encoding.UTF8.GetBytes(body));
    }

    await Task.CompletedTask;
}

在我的单元测试中,我希望确保回调事件被正确触发

[Theory]
[InlineData("Test 1", "Test 2", "Test 3")]
public async void SendMessageWithConfirm_MultipleMessages_ShouldPublishMessagesAndWaitForConfirmOrDie(
    params string[] messages)
{
    // Arrange
    var messageProducer = new RabbitMqMessageProducer(_connectionFactory);

    // Act
    await messageProducer.SendMessagesWithConfirmAsync(messages, "invitations", "invitation");

    // Assert
    _channel.Received(messages.Length).BasicPublish(Arg.Any<string>(), Arg.Any<string>(),
        null, Arg.Any<ReadOnlyMemory<byte>>());

    // Assert on callback events
    // ...
}

另一件事是_channel.NextPublishSeqNo永远不会递增。
如果您能提供任何帮助或推导出正确的文档,我们将不胜感激。

1zmg4dgp

1zmg4dgp1#

对rabbit的单元测试根本不应该检查rabbit服务器。对于rabbitMQ服务器,您应该添加集成测试。
在单元测试中,您要检查代码,因此必须添加模拟rabbit MQ服务器的模拟。
我使用Xunit nuget进行单元测试,使用moq nuget模拟rabbitMQ,如下所示:
单元测试:

[Fact]
public void publish__exchange_declare()
{
      //Arange
      var rabbitMQMoq = new RabbitMQMoq();

      //Act
      var pubRequest = rabbitMQMoq.Publish(new MockEvent());

       //Assert
       rabbitMQMoq.DefaultChannel.Verify(m => m.ExchangeDeclare(pubRequest.ExchangeName, pubRequest.ExchangeType.ToString().ToLower(), pubRequest.Durable, false, null));
}

模拟:

internal class RabbitMQMoq
    {
        #region consts

        public const string EXCHANGE_NAME = "TEST";
        public const string DLX_EXCHANGE_NAME = "DLX_TEST";
        public const string QUEUE_NAME = "TEST";
        public const string DLX_QUEUE_NAME = "DLX_TEST";
        public const string ROUTING_KEY = "TEST";
        public const string CONSUMER_TAG = "1234";
        public const ExchangeType EXCHNAGE_TYPE = ExchangeType.Topic;

        #endregion

        #region properties
        public Mock<IModel> DefaultChannel { get; private set; }
        public Mock<MockEventHandler> EventHandler { get; private set; }
        public Dictionary<string, IAsyncBasicConsumer> Consumers { get; private set; }
        public MojRabbitMQBus Bus { get; private set; }

        #endregion

        #region c-tor

        public RabbitMQMoq(HostConfiguration hostConfiguration= null)
        {
            DefaultChannel = new Mock<IModel>();
            Consumers = new Dictionary<string, IAsyncBasicConsumer>();
            EventHandler = new Mock<MockEventHandler>();
            Bus = CreateRabbitMQBService(hostConfiguration ?? DefaultHostConfiguration);
        }

  public PublishExchangeRequest<MockEvent> Publish(MockEvent mockEvent, PublishExchangeRequest<MockEvent> request = null)
        {
            var pubRequest = request ?? CreatePublishExchangeRequest(mockEvent);

            Bus.Publish(pubRequest);

            return pubRequest;
        }

 private Mock<IServiceScopeFactory> CreateServiceScopeFactory()
        {
            var serviceProvider = new Mock<IServiceProvider>();
            serviceProvider
          .Setup(x => x.GetService(typeof(MockEventHandler)))
          .Returns(EventHandler.Object);
            var serviceScope = new Mock<IServiceScope>();
            serviceScope.Setup(x => x.ServiceProvider).Returns(serviceProvider.Object);
            var serviceScopeFactory = new Mock<IServiceScopeFactory>();
            serviceScopeFactory
                .Setup(x => x.CreateScope())
                .Returns(serviceScope.Object);
            return serviceScopeFactory;
        }
}

相关问题