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