Martin
Martin

Reputation: 24308

.NET: HttpClient mocking it with my Interface IHttpClient, but there is an internal object that is NULL and it is sealed

I have created my own IHttpClient so I am able to mock HttpClient using moq. Works pretty well but there is an internal object called DetaultRequestHeaders which has a property called Authorization.

I am setting this in my constructor or my class that accepts in an injected IHttpClient, of course at runtime everything works as expected. But using Unit Tests I get an error saying

    Object reference not set to instance....

This is due to the fact that the DefaultRequestHeaders is null.

Now after inverstigating this further it appears that it is of type

    HttpRequestHeaders

but it's a sealed class so I can't even do this:

    .Setup(x => x.DefaultRequestHeaders).Returns(return new HttpRequestHeaders())

This is the interface definition

    HttpRequestHeaders DefaultRequestHeaders { get; }

Upvotes: 14

Views: 13792

Answers (3)

JoshSchlesinger
JoshSchlesinger

Reputation: 957

Just inject the concrete HttpClient and mock the underlying HttpMessageHandler...

http://geekswithblogs.net/abhi/archive/2013/11/20/unit-tests-for-httpclient-using-httpmessagehandler.aspx

You can unit test a class that uses HttpClient by giving that HttpClient a mock HttpMessageHandler. This way, you can capture the request and prevent it from actually going over the wire.

Here is an example using Moq. HttpClient depends on HttpMessageHandler’s SendAsync() method, so give SendAsync() a stub implementation and use Moq’s Callback() to capture arguments.

var handler = new Mock<HttpMessageHandler>();

handler.Protected()

    .Setup<Task<HttpResponseMessage>>("SendAsync", ItExpr.IsAny<HttpRequestMessage>(), ItExpr.IsAny<CancellationToken>())

    .Returns(Task<HttpResponseMessage>.Factory.StartNew(() =>

    {

        return new HttpResponseMessage(HttpStatusCode.OK);

    }))

    .Callback<HttpRequestMessage, CancellationToken>((r, c) =>

    {

        Assert.AreEqual(HttpMethod.Get, r.Method);

    });

 

using (var client = new HttpClient(handler.Object))

{

    var request = new HttpRequestMessage(HttpMethod.Get, "http://www.google.com");

    var response = client.SendAsync(request).Result;

    Console.WriteLine(response.StatusCode);

}

Upvotes: 17

wolszakp
wolszakp

Reputation: 1179

HttpRequestHeaders has only internal constructor. But you can do it by creating HttpRequestMesssage object:

var message = new HttpRequestMessage();
.Setup(x => x.DefaultRequestHeaders).Returns(message.Headers);

Upvotes: 4

Chris Mantle
Chris Mantle

Reputation: 6683

Your syntax on the Returns method call appears incorrect. The fact that HttpRequestHeaders is a sealed class shouldn't have any bearing on whether you can return an instance of it from a stubbed method call. Try changing that call to Returns(new HttpRequestHeaders()); or Returns(() => new HttpRequestHeaders());.

If that doesn't work (or the concrete implementation of HttpRequestHeaders is somehow unsuitable for your needs), you might need to try a framework that can mock sealed classes, perhaps Moles or JustMock.

Upvotes: -2

Related Questions