user7784348
user7784348

Reputation: 265

Azure Cosmos/Document DB ResourceResponse<Document> Unit test using Reflection Error

I am using the code snippet provided in below URL for instantiating ResourceResponse for unit test mocking purpose

https://github.com/Azure/azure-cosmosdb-dotnet/issues/342#issuecomment-367827999

But I am getting below error at given line:

var documentServiceResponse = Activator.CreateInstance(documentServiceResponseType, flags, null, arguments, null);

System.MissingMethodException: 'Constructor on type 'Microsoft.Azure.Documents.DocumentServiceResponse' not found.'

Ultimately I want to mock Response properties like RequestCharge.

Please suggest how t achieve that.

Thanks in advance

Upvotes: 2

Views: 992

Answers (1)

Nick Chapsas
Nick Chapsas

Reputation: 7200

You can do that by adding Cosmonaut's TestingExtensions

Here is an extension method that convert any object to a ResourceReponse.

public static ResourceResponse<T> ToResourceResponse<T>(this T resource, HttpStatusCode statusCode, IDictionary<string, string> responseHeaders = null) where T : Resource, new()
{
    var resourceResponse = new ResourceResponse<T>(resource);
    var documentServiceResponseType = Type.GetType("Microsoft.Azure.Documents.DocumentServiceResponse, Microsoft.Azure.DocumentDB.Core, Version=1.9.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35");

    var flags = BindingFlags.NonPublic | BindingFlags.Instance;

    var headers = new NameValueCollection { { "x-ms-request-charge", "0" } };

    if (responseHeaders != null)
    {
        foreach (var responseHeader in responseHeaders)
        {
            headers[responseHeader.Key] = responseHeader.Value;
        }
    }

    var arguments = new object[] { Stream.Null, headers, statusCode, null };

    var documentServiceResponse =
        documentServiceResponseType.GetTypeInfo().GetConstructors(flags)[0].Invoke(arguments);

    var responseField = typeof(ResourceResponse<T>).GetTypeInfo().GetField("response", BindingFlags.NonPublic | BindingFlags.Instance);

    responseField?.SetValue(resourceResponse, documentServiceResponse);

    return resourceResponse;
}

This will only work for pre-2.0.0 SDK versions.

For post 2.0.0 use this one instead.

public static ResourceResponse<T> ToResourceResponse<T>(this T resource, HttpStatusCode statusCode, IDictionary<string, string> responseHeaders = null) where T : Resource, new()
{
    var resourceResponse = new ResourceResponse<T>(resource);
    var documentServiceResponseType = Type.GetType("Microsoft.Azure.Documents.DocumentServiceResponse, Microsoft.Azure.DocumentDB.Core, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35");

    var flags = BindingFlags.NonPublic | BindingFlags.Instance;

    var headers = new NameValueCollection { { "x-ms-request-charge", "0" } };

    if (responseHeaders != null)
    {
        foreach (var responseHeader in responseHeaders)
        {
            headers[responseHeader.Key] = responseHeader.Value;
        }
    }

    var headersDictionaryType = Type.GetType("Microsoft.Azure.Documents.Collections.DictionaryNameValueCollection, Microsoft.Azure.DocumentDB.Core, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35");

    var headersDictionaryInstance = Activator.CreateInstance(headersDictionaryType, headers);

    var arguments = new [] { Stream.Null, headersDictionaryInstance, statusCode, null };

    var documentServiceResponse = documentServiceResponseType.GetTypeInfo().GetConstructors(flags)[0].Invoke(arguments);

    var responseField = typeof(ResourceResponse<T>).GetTypeInfo().GetField("response", flags);

    responseField?.SetValue(resourceResponse, documentServiceResponse);

    return resourceResponse;
}

You can read more about CosmosDB C# code unit testing here

Upvotes: 1

Related Questions