How to mock Azure Queue storage for unit test?

Viewed 3354

I want to mock QueueMessage for unit test,but I can not find any lib to mock

    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;
    }
3 Answers

Choice of Mocking lib would be an opinionated answer. There are several mocking frameworks available. One of the popular ones is Moq.

Using Moq, the sample test for your above code would look like below. Note that mocking storage lib is a bit tedious task as you can see.

        [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
        }

The constructors of the Queue models are internal, but you can create objects using the QueuesModelFactory which provides utilities for mocking.

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);

Try to mock the response of queueClient this will verify sendMessageAsync response

[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);
    }
Related