64
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.
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;
}
}
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 handleSendAsync
request. Return the json string asStringContent
- Mock
GraphServiceClient
ahd pass mockedIHttpProvider
as constructor - Mock
GetHttpRequestMessage
method as this is called inAddBatchRequestStep
[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);
}
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.
64