Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CloudTableClient Unit Testing

How do I write unit tests for classes that depend on Azure Table Storage, i.e. Microsoft.Azure.Cosmos.Table.CloudTableClient?

I found this GitHub issue, Azure Storage is still hard to unit test / mock, but I didn't find any clues in it other than methods are now virtual.


MyService takes a dependency on CloudTableClient and internally gets a reference to a CloudTable to query the table. In my example here I'm doing a simple lookup by partition and row key:

public MyService(CloudTableClient tableClient
            , ILogger<MyService> logger) { }

public async Task<MyMapping> GetMappingAsync(string rowKey)
{
    var table = GetTable();
    var retrieveOp = TableOperation.Retrieve<MyMapping>("MyPartitionKey", rowKey);
    var tableResult = await table.ExecuteAsync(retrieveOp);
    return tableResult.Result as MyMapping;
}

private CloudTable GetTable()
{
    return tableClient.GetTableReference("FakeTable");
}
like image 498
spottedmahn Avatar asked Nov 20 '19 15:11

spottedmahn


1 Answers

  1. Create a mock for CloudTable
    • Override the ExecuteAsync behavior via Setup
  2. Create a mock for CloudTableClient
    • Override the GetTableReference behavior to return the CloudTable mock via Setup
using Moq;
using Microsoft.Azure.Cosmos.Table;
using Microsoft.Extensions.Logging;
[TestInitialize]
public void InitTest()
{
    var cloudTableMock = new Mock<CloudTable>(new Uri("http://unittests.localhost.com/FakeTable")
        , (TableClientConfiguration)null);  //apparently Moq doesn't support default parameters 
                                            //so have to pass null here

    //control what happens when ExecuteAsync is called
    cloudTableMock.Setup(table => table.ExecuteAsync(It.IsAny<TableOperation>()))
        .ReturnsAsync(new TableResult());

    var cloudTableClientMock = new Mock<CloudTableClient>(new Uri("http://localhost")
        , new StorageCredentials(accountName: "blah", keyValue: "blah")
        , (TableClientConfiguration)null);  //apparently Moq doesn't support default parameters 
                                            //so have to pass null here

    //control what happens when GetTableReference is called
    cloudTableClientMock.Setup(client => client.GetTableReference(It.IsAny<string>()))
        .Returns(cloudTableMock.Object);

    var logger = Mock.Of<ILogger<MyService>>();
    myService = new MyService(cloudTableClientMock.Object, logger);
}
[TestMethod]
public async Task HelloWorldShouldReturnANullResult()
{
    //arrange
    var blah = "hello world";

    //act
    var result = await myService.GetMappingAsync(blah);

    //assert
    Assert.IsNull(result);
}
like image 119
spottedmahn Avatar answered Nov 17 '22 12:11

spottedmahn