8

How can I mock HttpRequestMessage, specifically the CreateResponse?

var requestMessage = Substitute.For<HttpRequestMessage>();
requestMessage.CreateResponse().ReturnsForAnyArgs(
       new HttpResponseMessage(HttpStatusCode.OK));

but I get the exception ...

NSubstitute.Exceptions.CouldNotSetReturnDueToNoLastCallException: 
  'Could not find a call to return from.

I've seen the questions ... How to mock the CreateResponse<T> extension method on HttpRequestMessage

And associated ... ASP.NET WebApi unit testing with Request.CreateResponse ...

But they don't seem to actually end up mocking the CreateResponse

Additional comments:

I'm trying to write a unit test around the starter of an Azure precompiled C# function ...

[FunctionName("Version")]
public static HttpResponseMessage Run(
    [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)]
    HttpRequestMessage req,
    TraceWriter log)
{
    log.Info("Version function processed a request ... ");

    return req.CreateResponse(HttpStatusCode.OK, "Version 0.0.1");
}

and the actual test, where I want to mock up the HttpRequestMessage, specifically the CreateReponse where I get the error is ...

[TestMethod]
public void Version_returns_value()
{
    var requestMessage = Substitute.For<HttpRequestMessage>();
    requestMessage.CreateResponse(Arg.Any<HttpStatusCode>(), Arg.Any<string>())
                  .Returns(new HttpResponseMessage(HttpStatusCode.OK));
    var log = new CustomTraceWriter(TraceLevel.Verbose);

    var httpResponseMessage = VersionFunction.Run(requestMessage, log);
    var httpContent = httpResponseMessage.Content;

    httpContent.Should().Be("Version 0.0.1 :: valid");
}
Nkosi
  • 235,767
  • 35
  • 427
  • 472
SteveC
  • 15,808
  • 23
  • 102
  • 173
  • 1
    NSubstitute (and other DynamicProxy-based libraries) can not mock extension methods. `HttpRequestMessage` does not have `virtual` members, so most mocking libraries will not help there either. Can you provide some more information on what you are trying to test? If mocking won't directly be of use here then we can discuss other options that might help. :) – David Tchepak Jul 24 '17 at 00:23
  • @DavidTchepak I've added more info to my question on what I'm trying to do ... – SteveC Jul 24 '17 at 11:59

1 Answers1

11

No need to mock anything here. Everything can be stubbed safely for this test. CreateResponse is an extension method that, internally, makes use of the request's associated HttpConfiguration. That is the only requirements that needs to be setup before using it in your test.

With that, if you update your test as follows, you should be able to properly exercise your test.

[TestMethod]
public async Task Version_returns_value() {
    var expected = "\"Version 0.0.1\"";
    var config = new HttpConfiguration();
    var requestMessage = new HttpRequestMessage();
    requestMessage.SetConfiguration(config);

    var log = new CustomTraceWriter(TraceLevel.Verbose);

    var httpResponseMessage = VersionFunction.Run(requestMessage, null);
    var httpContent = httpResponseMessage.Content;
    var content = await httpContent.ReadAsStringAsync();

    content.Should().Be(expected);
}
Nkosi
  • 235,767
  • 35
  • 427
  • 472
  • @Nkosi No joy I'm afraid ... Test method ChromebookFilterFunction.Tests.FunctionTests.Version_returns_value threw exception: System.MethodAccessException: Attempt by method 'System.Web.Http.HttpConfiguration..ctor(System.Web.Http.HttpRouteCollection)' to access method 'System.Web.Http.HttpConfiguration.DefaultFormatters()' failed. at System.Web.Http.HttpConfiguration..ctor(HttpRouteCollection routes) at System.Web.Http.HttpConfiguration..ctor() – SteveC Jul 24 '17 at 13:53
  • @SteveC I recreated you test minus the Trace and was able to run the test to completion with no exception exception for a slight mistake I made with the expected result. Is the code in your OP all the code or was something excluded that could be cause this error. – Nkosi Jul 24 '17 at 13:58
  • @Nkosi Firstly many thanks for responding, I really appreciate the help ... I've commented out the rest of the code in the file, and copy & pasted in your test ... still get the same MethodAccessException. I'm using preview 4 of VS 2017, as I'm working on pre-compiled Azure Functions, and that's got a lot of preview builds of some bits, but not System.Net.Http. That said, I've added a lot of NuGet packages to my test project in trying to get the tests to work, so maybe I've mess it up??? – SteveC Jul 24 '17 at 14:17
  • went back to a clean solution. The issue seems to be the use of HttpConfiguration from the System.Web.Http namespace. The tests compile locally, but when I try a build in VSTS, I'm getting build error ... Error CS0234: The type or namespace name 'Http' does not exist in the namespace 'System.Web' (are you missing an assembly reference?). – SteveC Jul 25 '17 at 12:05
  • You may need to check your NuGet packages. It probably does not have reference to the correct library – Nkosi Jul 25 '17 at 12:07