Mocking and unit testing graphql-dotnet

532 views Asked by At

I'm using graphql-dotnet library to query some GraphQL APIs from my C# code. Is there a way to easily mock the GraphQLHttpClient in unit tests?

2

There are 2 answers

1
Dawid Rutkowski On BEST ANSWER

It's not easy to mock the GraphQLHttpClient directly but you can provide your own HttpClient in one of the GraphQLHttpClient constructors and mock the HttpMessageHandler. Take a look a the code below:

HttpContent content = new StringContent(_responseContent, Encoding.UTF8, "application/json");
var response = new HttpResponseMessage
{
    StatusCode = HttpStatusCode.OK,
    Content = content
};

var httpMessageHandler = new Mock<HttpMessageHandler>();
httpMessageHandler.Protected()
                  .Setup<Task<HttpResponseMessage>>("SendAsync", ItExpr.IsAny<HttpRequestMessage>(), ItExpr.IsAny<CancellationToken>())
                  .ReturnsAsync(response);

HttpClient client = new HttpClient(httpMessageHandler.Object);

GraphQLHttpClient graphQlClient = new GraphQLHttpClient(GetOptions(), new NewtonsoftJsonSerializer(), client);

The above code works fine and allows me to provide any testing JSON output of the real GQL API I want in the _responseContent variable. The first line and two arguments - Encoding.UTF8, "application/json" - are quite important. Without providing the content type, the GraphQLHttpClient will throw an exception because of this line. It took me a while to find it.

I'm using Moq library for mocking objects.

0
AK94 On

The GraphQLHttpClient implements the IGraphQLWebSocketClient which extends the IGraphQLClient. The IGraphQLClient describes the following methods:

Task<GraphQLResponse<TResponse>> SendQueryAsync<TResponse>(GraphQLRequest request, CancellationToken cancellationToken = default);
        
Task<GraphQLResponse<TResponse>> SendMutationAsync<TResponse>(GraphQLRequest request, CancellationToken cancellationToken = default);

Then in your test code you can provide a moq for the IGraphQLClient. You only have to be aware that you are using Dependency Injection in combination with the provided interface.

It could be look like this here:

public class UnitTest1
{
   [Fact]
   public void Test1()
   {
      var mockedService = new Mock<IGraphQLClient>();
      mockedService
         Setup(ms => ms.SendQueryAsync<string>(It.IsAny<GraphQLRequest>(), It.IsAny<CancellationToken>()))
         .ReturnsAsync(new GraphQLResponse<string>());

         var service = new AnythingWithGraphQLDependency(mockedService.Object);

   }
}

public class AnythingWithGraphQLDependency
{
   private readonly IGraphQLClient _client;

   public AnythingWithGraphQLDependency(IGraphQLClient client)
   {
      _client = client;
   }

   public async Task<string> Test(string query, CancellationToken cancellationToken)
   {
      var response = await _client.SendQueryAsync<string>(new GraphQLRequest(query), cancellationToken);

      //Code to be tested goes here
   }
}