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
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;