Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unit test cosmosDb methods using Moq

Since there is no documentation for testing CosmosDb I am trying to do it myself but I have trouble doing it. For example I want to test an insert method that looks like this:

public async Task AddSignalRConnectionAsync(ConnectionData connection)
{
    if (connection != null)
    {
        await this.container.CreateItemAsync<ConnectionData>(connection, new PartitionKey(connection.ConnectionId));
    }
}

What I need to do is test if this method successfully create an item on the cosmosDb or at least fakes an successful creation. How can I test this?

like image 355
Kiril1512 Avatar asked Nov 08 '19 14:11

Kiril1512


1 Answers

In order to unit test that method in isolation, the dependencies of the class under test would need to be mocked.

Assuming an example like the following

public class MySubjectClass {
    private readonly Container container;

    public MySubjectClass(Container container) {
        this.container = container;
    }

    public async Task AddSignalRConnectionAsync(ConnectionData connection) {
        if (connection != null) {
            var partisionKey = new PartitionKey(connection.ConnectionId);
            await this.container.CreateItemAsync<ConnectionData>(connection, partisionKey);
        }
    }        
}

In the above example, the method under test is dependent on Container and ConnectionData, which need to be provided when testing.

Unless you want to hit an actual instance of the Container it would be recommended to mock dependencies that can have undesirable behavior if an actual implementation is used.

public async Task Should_CreateItemAsync_When_ConnectionData_NotNull() {
    //Arrange
    //to be returned by the called mock
    var responseMock = new Mock<ItemResponse<ConnectionData>>();

    //data to be passed to the method under test
    ConnectionData data = new ConnectionData {
        ConnectionId = "some value here"
    };

    var containerMock = new Mock<Container>();
    //set the mock expected behavior
    containerMock
        .Setup(_ => _.CreateItemAsync<ConnectionData>(
            data, 
            It.IsAny<PartitionKey>(), 
            It.IsAny<ItemRequestOptions>(),
            It.IsAny<CancellationToken())
        )
        .ReturnsAsync(responseMock.Object)
        .Verifiable();

    var subject = new MySubjectClass(containerMock.Object);

    //Act
    await subject.AddSignalRConnectionAsync(data);

    //Assert
    containerMock.Verify(); //verify expected behavior
}

The subject method under test can be verified that it will call the expected method when the parameter is not null based on the above isolated unit test example.

Using a real Container would make this an integration test, which would require a different kind of test arrangement.

You could also check how the developers unit test the SDK here

https://github.com/Azure/azure-cosmos-dotnet-v3/tree/master/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests

Credit: @MatiasQuaranta

like image 119
Nkosi Avatar answered Oct 16 '22 12:10

Nkosi