How to mock a BlobBatchClient to be used in unit tests

Angela Calborean 71 Reputation points
2024-03-13T11:07:50.1933333+00:00

Hello,

In my project, we need to change the tier of multiple blobs and for this we use: await blobBatchClient.SetBlobsAccessTierAsync

The problem is how to add unit tests for this code:

First attempt:

        var blobBatchClient = new Mock<BlobBatchClient>();
        var blobServiceClient = new Mock<BlobServiceClient>();
        blobServiceClient.Setup(m => m.GetBlobContainerClient(It.IsAny<string>())).Returns(blobContainerClient.Object);
        blobServiceClient.Setup(m => m.GetBlobBatchClient()).Returns(blobBatchClient.Object);

Returns this error:

Unsupported expression: m => m.GetBlobBatchClient()

Extension methods (here: SpecializedBlobExtensions.GetBlobBatchClient) may not be used in setup / verification expressions.

Second attempt: mock the BlobContaineClient and pass it to the constructor of BlobBatchClient, but it does not work either.

       var blobContainerClient = new Mock<BlobContainerClient>();
       blobContainerClient.Setup(m => m.Name).Returns(Guid.NewGuid().ToString);
       blobContainerClient.Setup(m => m.Uri).Returns(new Uri("https://test.com"));
       var blobBatchClient = new BlobBatchClient(blobContainerClient.Object);
Azure Storage Accounts
Azure Storage Accounts
Globally unique resources that provide access to data management services and serve as the parent namespace for the services.
2,820 questions
Azure Blob Storage
Azure Blob Storage
An Azure service that stores unstructured data in the cloud as blobs.
2,546 questions
0 comments No comments
{count} votes

Accepted answer
  1. Azar 20,680 Reputation points
    2024-03-13T12:19:05.86+00:00

    Hey there Angela Calborean

    Thats a good question and thanks for using QandA platform.

    So Since Moq doesn't support mocking extension methods directly, it's best to abstract away the creation of BlobBatchClient in your production code. Create an interface that represents the functionality you need from BlobBatchClient, and then implement that interface in a class that internally uses BlobBatchClient.

    Inject the interface representing the BlobBatchClient functionality into the classes.

    public interface IBlobBatchClientWrapper
    {
        Task SetBlobsAccessTierAsync(IEnumerable<Uri> blobUris, AccessTier tier, CancellationToken cancellationToken = default);
    }
    public class BlobBatchClientWrapper : IBlobBatchClientWrapper
    {
        private readonly BlobBatchClient _blobBatchClient;
        public BlobBatchClientWrapper(BlobServiceClient blobServiceClient)
        {
            _blobBatchClient = blobServiceClient.GetBlobBatchClient();
        }
        public async Task SetBlobsAccessTierAsync(IEnumerable<Uri> blobUris, AccessTier tier, CancellationToken cancellationToken = default)
        {
            // Delegate the actual functionality to the BlobBatchClient instance
            await _blobBatchClient.SetBlobsAccessTierAsync(blobUris, tier, cancellationToken);
        }
    }
    
    

    Now, in your production code, use IBlobBatchClientWrapper instead of directly using BlobBatchClient.

    For your unit tests, you can now easily mock IBlobBatchClientWrapper using Moq

    var blobBatchClientWrapperMock = new Mock<IBlobBatchClientWrapper>();
    blobBatchClientWrapperMock.Setup(m => m.SetBlobsAccessTierAsync(It.IsAny<IEnumerable<Uri>>(), It.IsAny<AccessTier>(), It.IsAny<CancellationToken>()))
        .Returns(Task.CompletedTask);
    
    var myService = new MyService(blobBatchClientWrapperMock.Object);
    
    
    

    If this helps kindly accept the answer thanks much.

    1 person found this answer helpful.
    0 comments No comments

0 additional answers

Sort by: Most helpful