单元测试 运行 永远用于 C# 中的回调方法

Unit test running forever for call back method in C#

以下是RabbitMq Queue接收消息的方法。方法工作正常,但是单元测试这个方法有下面提到的问题

      public void GetMessage(Action<string> action)
    {
        //create a connection factory
        var factory = new ConnectionFactory();

        if (_connectionString != null)
        {
            //assign connection string of rabbitmq
            factory.Uri = new Uri(_connectionString);
        }

        //create connection and channel from connectionfactory
        using (var connection = factory.CreateConnection())
        using (var channel = connection.CreateModel())
        {

            //declare the queque on the channel
            channel.QueueDeclare(queue: _queque,
                                 durable: false,
                                 exclusive: false,
                                 autoDelete: false,
                                 arguments: null);

            //create consumer using the channel
            var consumer = new EventingBasicConsumer(channel);
            consumer.Received += (model, ea) =>
            {
                //When message is recieved on the consumer this will be triggered
                var body = ea.Body.ToArray();
                _message = Encoding.UTF8.GetString(body);

                //call the method passed by the caller method
                action(_message);
            };

            //add the consumer on this channel
            channel.BasicConsume(queue: _queque,
                                 autoAck: true,
                                 consumer: consumer);

            Console.ReadLine();
        }

    }

如何编写单元测试测试上面的消息。下面的单元测试在回调方法中永远加载并且执行永远不会进入 Assert.Equal 行。

      [Fact]
    public async Task AddMessageAsync_ShouldAddToQueue()
    {
        //Arrange
        string messageToSend = "Test";
        string recievedMessage = null;
        var queue = GetQueueManager();

        queue.Message = messageToSend;

        await queue.AddMessageAsync();

        //Act
        queue.GetMessage((string message) =>
        {
            //Hit here and recieved the message but does not exist from this method
            recievedMessage = message;
        });

        //Assert
        Assert.Equal(messageToSend, recievedMessage);
    }

解决该问题的一种方法是同步障碍。 这是一个示例:(不过,可能还有更有效的方法。)

... // Your code with some changes:
//create connection and channel from connectionfactory
        using (var connection = factory.CreateConnection())
        using (var channel = connection.CreateModel())
        {

            //declare the queque on the channel
            channel.QueueDeclare(queue: _queque,
                                 durable: false,
                                 exclusive: false,
                                 autoDelete: false,
                                 arguments: null);
            
            // Set up a synchronization barrier.
            using (var barrier = new ManualResetEventSlim(false))
            {

                //create consumer using the channel
                var consumer = new EventingBasicConsumer(channel);
                consumer.Received += (model, ea) =>
                {
                //When message is recieved on the consumer this will be triggered
                    var body = ea.Body.ToArray();
                    _message = Encoding.UTF8.GetString(body);

                    try // you don't want "injected" code to break yours.
                    {
                        //call the method passed by the caller method
                        action(_message);
                    }
                    catch(Exception)
                    {
                        // at least log it!
                    }
                    finally
                    {
                        barrier.Set(); // Signal Event fired.
                    }
                };

                //add the consumer on this channel
                channel.BasicConsume(queue: _queque,
                                     autoAck: true,
                                     consumer: consumer);
 
                barrier.Wait(); // Wait for Event to fire.
            }
        }

我想 RabbitMQ API 有一个更新来支持 async/await 而不是 event-based?如果是这样,那么使用它当然是更可取的。

如果没有:您可能还想探索 Tasks and the Event-based Asynchronous Pattern (EAP)