DEV Community

Kenichiro Nakamura
Kenichiro Nakamura

Posted on

C# : How to unit test Graph SDK Batch Request

Even though writing unit tests for Azure Graph SDK became easier, writing unit test for Batch request was little bit confusing to me.

Source Code

This is my class which I want to write unit test. I omit some business logic on purpose, this is not simple wrapper in real project.

  • DI GraphServiceClient
  • Return User objects via Batch Request
  • Use AddBatchRequestStep to control requestId
public class GraphService
{
    private readonly GraphServiceClient graphServiceClient;

    public GraphService(GraphServiceClient graphServiceClient)
    {
        this.graphServiceClient = graphServiceClient;
    }

    public async Task<List<User>> GetUsersAsync(List<string> userIds)
    {
        List<User> users = new();
        BatchRequestContent batchRequestContent = new();
        userIds.ForEach(x =>
        {
            batchRequestContent.AddBatchRequestStep(new BatchRequestStep(x, graphServiceClient.Users[x]
                    .Request().Select(u => new
                    {
                        u.Id,
                        u.GivenName,
                        u.Mail,
                        u.Surname,
                        u.UserPrincipalName
                    }).GetHttpRequestMessage()));
        });

        BatchResponseContent returnedResponse = await graphServiceClient.Batch.Request().PostAsync(batchRequestContent);
        userIds.ForEach(async x =>
        {
            User user = await returnedResponse.GetResponseByIdAsync<Microsoft.Graph.User>(x);
            users.Add(user);
        });

        return users;
    }
}
Enter fullscreen mode Exit fullscreen mode

Unit Test Code

I don't know if there is better way to achieve the same, but this is what I did by following advice in GitHub issue

  • Create response as json string
  • Mock IHttpProvider to handle SendAsync request. Return the json string as StringContent
  • Mock GraphServiceClient ahd pass mocked IHttpProvider as constructor
  • Mock GetHttpRequestMessage method as this is called in AddBatchRequestStep
[Fact]
public async Task ReturnsUsers()
{
    // Arrenge
    string userId = "dummy_id1";
    string userId2 = "dummy_id2";
    string batchResponse = @$"{{
""responses"":[{{
    ""id"": ""{userId}"",
    ""status"":200,
    ""headers"":
    {{
        ""Content-Type"":""application/json""
    }},
    ""body"":
    {{
        ""@odata.context"":""https://graph.microsoft.com/v1.0/$metadata#users/$entity"",
        ""surName"":""Test"",
        ""givenName"":""User1"",
        ""id"":""{userId}""
    }}
  }},
{{
    ""id"": ""{userId2}"",
    ""status"":200,
    ""headers"":
    {{
        ""Content-Type"":""application/json""
    }},
    ""body"":
    {{
        ""@odata.context"":""https://graph.microsoft.com/v1.0/$metadata#users/$entity"",
        ""surName"":""Test"",
        ""givenName"":""User2"",
        ""id"":""{userId2}""
    }}
  }}]
}}";
    Mock<IHttpProvider> mockedIHttpProvider = new();
    mockedIHttpProvider.Setup(x => x.SendAsync(
        It.IsAny<HttpRequestMessage>(), 
        It.IsAny<HttpCompletionOption>(), 
        It.IsAny<CancellationToken>()))
        .ReturnsAsync(new HttpResponseMessage()
        {
            StatusCode = HttpStatusCode.OK,
            Content = new StringContent(batchResponse),
        });
    Mock<IAuthenticationProvider> mockedIAuthenticationProvider = new();
    Mock<GraphServiceClient> mockedGraphServiceClient = new(
        mockedIAuthenticationProvider.Object, mockedIHttpProvider.Object);
    mockedGraphServiceClient.Setup(x => x.Users[It.IsAny<string>()]
        .Request()
        .Select(It.IsAny<Expression<Func<Microsoft.Graph.User, object>>>()).GetHttpRequestMessage())
        .Returns(new HttpRequestMessage() { RequestUri = new Uri("http://localhost/v1.0/users") });
    GraphService graphService = new(mockedGraphServiceClient.Object);

    // Act
    List<User> users = await graphService.GetUsersAsync(new List<string>() { userId, userId2 }).ConfigureAwait(false);

    // Assert
    Assert.True(users.Count == 2);
}
Enter fullscreen mode Exit fullscreen mode

Summary

There are several trips required so I wish I can find better/easier way to achieve it in the future.

Of course we can mock any behavior and objects. Simply change request and response.

👋 While you are here

Reinvent your career. Join DEV.

It takes one minute and is worth it for your career.

Get started

Top comments (0)

Billboard image

The Next Generation Developer Platform

Coherence is the first Platform-as-a-Service you can control. Unlike "black-box" platforms that are opinionated about the infra you can deploy, Coherence is powered by CNC, the open-source IaC framework, which offers limitless customization.

Learn more

👋 Kindness is contagious

Engage with a sea of insights in this enlightening article, highly esteemed within the encouraging DEV Community. Programmers of every skill level are invited to participate and enrich our shared knowledge.

A simple "thank you" can uplift someone's spirits. Express your appreciation in the comments section!

On DEV, sharing knowledge smooths our journey and strengthens our community bonds. Found this useful? A brief thank you to the author can mean a lot.

Okay