'How to mock response in FHIR Http Client calls to CreateAsync

When implementing calls to CreateAsync in the Hl7.Fhir.Rest.FhirClient library I'm struggling with how to mock a valid response. I know how to mock the dotnet-httpclient using a Mock HttpMessageHandler object and noticed there is a message handler argument that can be specified when creating the FhirClient. What I have tried to do is specify a message handler to the creation step that is a mock message handler object.

This simplified unit test attempts to mock the HttpMessageHandler and cause it to return a valid body and result code from the FhirClient's CreateAsync method call.

        [Fact]
        public async Task SubscribeAndReturnSubscriptionIdAsync()
        {
            var mockHttpMessageHandler = MockFhirHttpClientMessageHandler.MockSubscribeMessageResponse(new StringContent("{'id':'abc123','status':'active'}"), HttpStatusCode.Created);
            var subscriptionResource = new Subscription()
            {
                Criteria = "https://server.fire.ly/CareTeam",
                Status = Subscription.SubscriptionStatus.Active,
                Reason = "test",
                Channel = new Subscription.ChannelComponent()
                {
                    Type = Subscription.SubscriptionChannelType.RestHook,
                    Endpoint = "http://localhost:9999/AscomFhirApi/UpdateCareTeam",
                    Payload = "application/fhir+json"
                },
            };
            var serverUri = new Uri("http://server.fire.ly");
            var clientSettings = new FhirClientSettings()
            {
                PreferredFormat = ResourceFormat.Json
            };

            var fhirHttpClient = new Hl7.Fhir.Rest.FhirClient(serverUri, clientSettings, mockHttpMessageHandler.Object);

            var subscription = await fhirHttpClient.CreateAsync<Subscription>(subscriptionResource);

            Assert.NotEmpty(subscription.Id);
        }

The MockSubscribeMessageResponse method shown below creates the HttpMessageHandler that is passed to the FhirClient in the above test.

public static Mock<HttpMessageHandler> MockSubscribeMessageResponse(
            HttpContent content,
            HttpStatusCode code = HttpStatusCode.OK)
        {
            var mockHttpMessageHandler = new Mock<HttpMessageHandler>();
            mockHttpMessageHandler.Protected()
                .Setup<Task<HttpResponseMessage>>("SendAsync", ItExpr.IsAny<HttpRequestMessage>(),
                    ItExpr.IsAny<CancellationToken>())
                .ReturnsAsync(new HttpResponseMessage
                {
                    StatusCode = code,
                    Content = content
                });
            return mockHttpMessageHandler;
        }

The error I'm getting is a Null Reference Exception in what looks like the HttpResponseMessage or response body.

System.NullReferenceException
Object reference not set to an instance of an object.
   at Hl7.Fhir.Rest.HttpToEntryExtensions.ToEntryResponse(HttpResponseMessage response, Byte[] body)
   at Hl7.Fhir.Rest.HttpClientRequester.ExecuteAsync(EntryRequest interaction)
   at Hl7.Fhir.Rest.BaseFhirClient.executeAsync[TResource](Bundle tx, IEnumerable`1 expect)
   at Tests.Unit.Core.Services.FirelyHttpClientShould.SubscribeAndReturnSubscriptionIdAsync() in C:\src\AscomIASharedAssignFHIRApi5\Tests.Unit.Core\Services\FirelyHttpClientShould.cs:line 60


Solution 1:[1]

You have probably figured this out long time ago, but the source of error is most probably missing RequestMessage, implementation of ToEntryResponse depends on response.RequestMessage.RequestUri being set. So I guess that what you need to do is:

var mockHttpMessageHandler = new Mock<HttpMessageHandler>();
mockHttpMessageHandler.Protected()
    .Setup<Task<HttpResponseMessage>>("SendAsync", ItExpr.IsAny<HttpRequestMessage>(), ItExpr.IsAny<CancellationToken>())
    .ReturnsAsync(new HttpResponseMessage
    {
        StatusCode = code,
        RequestMessage = new HttpRequestMessage(HttpMethod.Get, "http://localhost"),
        Content = content
    });
    return mockHttpMessageHandler;

Solution 2:[2]

A long time later again ... In version 3.8.3 of the Firely SDK the FhirClient now has support for taking the HttpClient in its constructor, so this may make unit testing apis much easier. It wasn't clear from your post what you were testing here...

I wrote a blog post on using it for this type of testing

Roughly something like ...

[TestMethod]
public async Task SubscribeAndReturnSubscriptionIdAsync()
{
    using (var fhirServerFactory = new UnitTestFhirServerApplication())
    using (var httpclient = fhirServerFactory.CreateClient())
    {
        var server = new FhirClient("http://server.fire.ly", httpclient);
        var subscriptionResource = new Subscription()
            {
                Criteria = "https://server.fire.ly/CareTeam",
                Status = Subscription.SubscriptionStatus.Active,
                Reason = "test",
                Channel = new Subscription.ChannelComponent()
                {
                    Type = Subscription.SubscriptionChannelType.RestHook,
                    Endpoint = "http://localhost:9999/AscomFhirApi/UpdateCareTeam",
                    Payload = "application/fhir+json"
                },
            };
        var subscription = await server.CreateAsync(subscriptionResource);
        // ...
    }
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Tyler2P
Solution 2 Brian Postlethwaite