如何模拟 Azure 队列存储以进行单元测试?

Posted

技术标签:

【中文标题】如何模拟 Azure 队列存储以进行单元测试?【英文标题】:How to mock Azure Queue storage for unit test? 【发布时间】:2020-11-27 14:39:47 【问题描述】:

我想模拟 QueueMessage 进行单元测试,但我找不到任何要模拟的库

    public  async Task<QueueMessage[]> ReceiveMessagesAsync(QueueClient queue)
       
     
        QueueProperties properties = queue.GetProperties();

        // Retrieve the cached approximate message count.
        int cachedMessagesCount = properties.ApproximateMessagesCount;
        QueueMessage[] queueMessages =new QueueMessage[cachedMessagesCount];

        int num = cachedMessagesCount / 32;

        for (int i = 0; i < num + 1; i++)
        
         var  messages = await queue.ReceiveMessagesAsync(maxMessages: 32);
         messages.Value.CopyTo(queueMessages,i*32);
        
        return queueMessages;
    

【问题讨论】:

模拟 EAI 系统 的各个方面有什么意义?消息只是信封。你想要有效载荷。测试有效载荷的处理程序不是更好吗? well-written system 的业务逻辑应该与任何 EAI 系统解耦 @MickyD 感谢您的评论!你真的明白了,我通过返回 QueueMessage.MessageText 而不是对象本身解决了这个不需要的问题。绝对正确的观点,需要考虑! 【参考方案1】:

队列模型的构造函数是内部的,但您可以使用QueuesModelFactory 创建对象,它提供了用于模拟的实用程序。

QueueMessage queueMsg = QueuesModelFactory.QueueMessage(
    messageId: "id2", 
    popReceipt: "pr2", 
    body: JsonConvert.SerializeObject("Test"), 
    dequeueCount: 1, 
    insertedOn: DateTimeOffset.UtcNow);

 var metadata = new Dictionary<string, string>   "key", "value" , ;
 int messageCount = 5;
 QueueProperties queueProp = QueuesModelFactory.QueueProperties(metadata, messageCount);

【讨论】:

【参考方案2】:

Mocking lib 的选择将是一个固执己见的答案。有几个可用的模拟框架。最受欢迎的之一是Moq。

使用最小起订量,您的上述代码的示例测试如下所示。请注意,如您所见,模拟存储库是一项有点乏味的任务。

        [Test]
        public async Task ReceiveMessagesAsync_StateUnderTest_ExpectedBehavior()
        
            // Arrange
            var queueClientHelper = new QueueClientHelper();
            var queueMock = new Mock<QueueClient>();
            var mockPropertiesResponse = new Mock<Response<QueueProperties>>();
            var properties = new QueueProperties();
            properties.GetType().GetProperty(nameof(properties.ApproximateMessagesCount), BindingFlags.Public | BindingFlags.Instance).SetValue(properties, 64); // little hack since ApproximateMessagesCount has internal setter
            mockPropertiesResponse.SetupGet(r => r.Value).Returns(properties);
            queueMock.Setup(q => q.GetProperties(It.IsAny<CancellationToken>())).Returns(mockPropertiesResponse.Object);
            var mockMessageReponse = new Mock<Response<QueueMessage[]>>();
            mockMessageReponse.SetupGet(m => m.Value).Returns(new QueueMessage[32]);
            queueMock.Setup(q => q.ReceiveMessagesAsync(It.IsAny<int?>(), It.IsAny<TimeSpan?>(), It.IsAny<CancellationToken>())).ReturnsAsync(mockMessageReponse.Object);

            // Act
            var result = await queueClientHelper.ReceiveMessagesAsync(queueMock.Object);

            // Assert
            Assert.AreEqual(64, result.Length);
            // verify mocks as required
        

【讨论】:

非常感谢!天哪【参考方案3】:

尝试模拟 queueClient 的响应,这将验证 sendMessageAsync 响应

[Fact]
    public async Task SendMessage_ShouldReturnSuccess()
    
        var receipt = QueuesModelFactory.SendReceipt("1", DateTimeOffset.Now, DateTimeOffset.Now.AddDays(2), "pop", DateTimeOffset.Now.AddDays(1));
        var res = Response.FromValue<SendReceipt>(receipt, null);
        var queueClientmock = new Mock<QueueClient>();
        queueClientmock.Setup(q => q.SendMessageAsync(It.IsAny<string>())).Returns(Task.FromResult(res));
        var sqmock = new Mock<IStorageQueueProvider>();
        sqmock.Setup(s => s.GetStorageQueueClient()).Returns(Task.FromResult(queueClientmock.Object)).Verifiable();
        var storageQueueRepository = new StorageQueueRepository(sqmock.Object, DummyLogger);
        var result = await storageQueueRepository.SendMessage("test message");
        result.StatusCode.Should().Be(HttpStatusCode.OK);
    

【讨论】:

以上是关于如何模拟 Azure 队列存储以进行单元测试?的主要内容,如果未能解决你的问题,请参考以下文章

如何模拟 acegi 身份验证服务以进行单元测试?

Vue,vuex:如何使用命名空间存储和模拟对组件进行单元测试?

如何模拟 mongodb 以进行单元测试 graphql 解析器

用玩笑进行单元测试时,如何以角度模拟 ResizeObserver polyfill?

如何在 Angular 组件中模拟服务功能以进行单元测试

您如何在 C# 中模拟文件系统以进行单元测试?