How to make mocked unit test for Azure Storage

As you have seen I have published 3 articles series on How to make integration test for Azure Storage. Mean while a few of you wrote to me on how can I make mocked unit test of the same methods that I presented in my article part 2.

As you remember, we created a empty solution in Visual Studio 2022 and call it AzureBlobStorageApp. Than I will create my first library project and call it AzureBlobStorageApp .

I add Azure.Storage.Blobs NuGet package to my project.

<ItemGroup>
  <PackageReference Include="Azure.Storage.Blobs" Version="12.10.0" />
</ItemGroup>

Now lets create a class AzureBlobStorage.cs with a constructor that takes connection string and container name.

public AzureBlobStorage(string connectionString, string container)
{
    _blobContainerClient = new BlobContainerClient(connectionString, container);
    _blobContainerClient.CreateIfNotExists();
}

We will create 3 methods that Read, Create and Delete text file.

public async Task<string> ReadTextFile(string filename)
{
    var blob = _blobContainerClient.GetBlobClient(filename);
    if (!await _blobContainerClient.ExistsAsync()) return string.Empty;
    var reading = await blob.DownloadStreamingAsync();
    StreamReader reader = new StreamReader(reading.Value.Content);
    return await reader.ReadToEndAsync();
}

public async Task CreateTextFile(string filename, byte[] data)
{
    var blob = _blobContainerClient.GetBlobClient(filename);
    await using var ms = new MemoryStream(data, false);
    await blob.UploadAsync(ms, CancellationToken.None);
}

public async Task DeleteTextFile(string filename)
{
    var blobClient = _blobContainerClient.GetBlobClient(filename);
    await blobClient.DeleteAsync();
}

public int NumberOfBlobs()
{
    var blobClient = _blobContainerClient.GetBlobs();
    return blobClient.Count();
}

For the above methods, I have created an interface call it IAzureBlobStorage that contains the methods and signature, as we need this interface later for mocking of our methods:

public interface IAzureBlobStorage
{
    public Task<string> ReadTextFile(string filename);
    public Task CreateTextFile(string filename, byte[] data);
    public Task DeleteTextFile(string filename);
    public int NumberOfBlobs();
}

Now we create a new xunit test project and call it AzureBlobStorageApp.UnitTests

Check and eventually adding following dependencies, and of course add reference to our AzureBlobStorageApp project as well.

<ItemGroup>
    <PackageReference Include="Azure.Storage.Blobs" Version="12.10.0" />
    <PackageReference Include="Docker.DotNet" Version="3.125.5" />
    <PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="6.0.0" />
    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" />
    <PackageReference Include="Moq" Version="4.16.1" />

    <PackageReference Include="xunit" Version="2.4.1" />
    <PackageReference Include="xunit.console" Version="2.4.1" />
    <PackageReference Include="xunit.runner.console" Version="2.4.1">
        <PrivateAssets>all</PrivateAssets>
        <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
    </PackageReference>
    <PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
        <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
        <PrivateAssets>all</PrivateAssets>
    </PackageReference>
</ItemGroup>

<ItemGroup>
    <ProjectReference Include="..\AzureBlobStorageApp\AzureBlobStorageApp.csproj" />
</ItemGroup>

Lets create a class AzureBlobStorageMockUnitTests, and creating our first unit test:

[Fact]
public async Task AzureBlobStorageTest()
{
    // Arrange
    var mock = new Mock<IAzureBlobStorage>();

    mock
        .Setup(azureBlobStorage => azureBlobStorage.CreateTextFile(It.IsAny<string>(), It.IsAny<byte[]>()))
        .Callback(() =>
        {
            mock.Setup(azureBlobStorage => azureBlobStorage.ReadTextFile(It.IsAny<string>()))
                .Returns(async () => await Task.FromResult(Content));
            mock.Setup(azureBlobStorage => azureBlobStorage.NumberOfBlobs())
                .Returns(1);
        });

    mock
        .Setup(azureBlobStorage => azureBlobStorage.DeleteTextFile(It.IsAny<string>()))
        .Callback(() =>
        {
            mock.Setup(azureBlobStorage => azureBlobStorage.ReadTextFile(It.IsAny<string>()))
                .Returns(async () => await Task.FromResult(string.Empty));
            mock.Setup(azureBlobStorage => azureBlobStorage.NumberOfBlobs())
                .Returns(0);
        });

    // Act
    await mock.Object.CreateTextFile("file.txt", Encoding.UTF8.GetBytes(Content));
    var readTextFile = await mock.Object.ReadTextFile("file.txt");
    var filesCount = mock.Object.NumberOfBlobs();

    // Assert
    Assert.Equal(Content, readTextFile);
    Assert.Equal(1, filesCount);

    // Finalizing Act
    await mock.Object.DeleteTextFile("file.txt");
    var readTextFileAfterDelete = await mock.Object.ReadTextFile("file.txt");
    var filesCountAfterDelete = mock.Object.NumberOfBlobs();

    // Finalizing Assert
    Assert.Equal(string.Empty, readTextFileAfterDelete);
    Assert.Equal(0, filesCountAfterDelete);
}

My test might be not very innovative, but it is to give some idea how to do mocking. So what we do here is we say each time we Call CreateTextFile, a result of that we need method ReadTextFile return us the file that we created. And count up the amount of files in our blob.

The same when we call DeleteTextFile, we do the opposite. By delete the file content and decrease our count to zero.

This way, we ensure if some one change our methods and not following our test expectation, by change the signature, or returning some not expected value, our test will break.

Now lets fire up our test, remember your azurite docker should be up and running.

Mocked Unit Test

Congrats, now you have just learned how to mock unit test your methods that for Azure Blob Storage on local environment.

Download the project from GitHub.

Conclusion

In this article, we learned to how to mock unit test Azure Blob Storage methods.

If you really need to make integration test with out specific Azure Cloud account or Environment, see my 3 articles series.

I would also in addition reference to this article from Microsoft.

Graphic credit
The banner in this article is design by my ❤️ 15 years son Jassin Fahmi 😀.

Leave a Comment