Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unit testing DelegatingHandler

How do I unit test a custom DelegatingHandler? I have the following but its complaining the innerHandler not set.

var httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, "http://foo.com");
var handler = new FooHandler()
{
    InnerHandler = new FooHandler() 
};

var invoker = new HttpMessageInvoker(handler);
var result = await invoker.SendAsync(httpRequestMessage, new CancellationToken());

Assert.That(result.Headers.GetValues("some-header").First(), Is.Not.Empty, "");
like image 277
Dr Schizo Avatar asked Jul 27 '15 10:07

Dr Schizo


3 Answers

You can set the InnerHandler property of the DelegatingHandler you're testing (FooHandler) with a dummy/fake handler (TestHandler) as shown in that linked post in your comment.

public class TestHandler : DelegatingHandler
{
    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        return Task.Factory.StartNew(() => new HttpResponseMessage(HttpStatusCode.OK), cancellationToken);
    }
}

 // in your test class method
    var httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, "https://example.com/");
    var handler = new FooHandler()
    {
        InnerHandler = new TestHandler()  // <-- change to use this

    };

    var invoker = new HttpMessageInvoker(handler);
    var result = await invoker.SendAsync(httpRequestMessage, new CancellationToken());

    Assert.That(result.Headers.GetValues("some-header").First(), Is.Not.Empty, "");

Unlike that post, this should be the minimum you need to set up to get your test to run.

like image 82
Ray Avatar answered Oct 20 '22 10:10

Ray


With using Moq.Protected;, you can get more control over the response outcome.

var request = new HttpRequestMessage();

var innerHandlerMock = new Mock<DelegatingHandler>(MockBehavior.Strict);
innerHandlerMock
  .Protected()
  .Setup<Task<HttpResponseMessage>>("SendAsync", request, ItExpr.IsAny<CancellationToken>())
  .ReturnsAsync(new HttpResponseMessage(HttpStatusCode.OK));

var handler = new FooHandler()
{
  InnerHandler = innerHandlerMock.Object
};
var invoker = new HttpMessageInvoker(handler);

// act
await invoker.SendAsync(request, default);
like image 36
rdvanbuuren Avatar answered Oct 20 '22 11:10

rdvanbuuren


Use e.g. System.Net.Http.HttpClientHandler or System.Web.Http.HttpServer as an InnerHandler:

var handler = new FooHandler()
{
    InnerHandler = new System.Net.Http.HttpClientHandler()
};

or

var handler = new FooHandler()
{
    InnerHandler = new System.Web.Http.HttpServer() 
};
like image 45
Andriy Tolstoy Avatar answered Oct 20 '22 10:10

Andriy Tolstoy