I have a function that I'm porting from Azure Functions v1 to v2, and as part of that I've run into an issue updating my unit tests which create a stubbed HttpRequestMessage. Here's the code that works on Functions v1, targeting .NET Framework 4.7
public class FunctionExample
{
[FunctionName(nameof(SomeFunction))]
public static async Task<HttpResponseMessage> SomeFunction
(
[HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = "SomeFunction")]
HttpRequestMessage request
)
{
var body = await request.Content.ReadAsStringAsync();
if (string.IsNullOrEmpty(body))
{
return request.CreateResponse(HttpStatusCode.BadRequest, "Bad job");
}
else
{
return request.CreateResponse(HttpStatusCode.OK, "Good job");
}
}
}
And my test code
public class FunctionExampleTests
{
[Test]
public async Task TestSomeFunction()
{
var request = new HttpRequestMessage
{
Method = HttpMethod.Post,
RequestUri = new Uri("http://localhost/"),
Content = new StringContent("", Encoding.UTF8, "application/json")
};
request.Properties.Add(HttpPropertyKeys.HttpConfigurationKey,
new HttpConfiguration());
var response = await FunctionExample.SomeFunction(request);
var content = await response.Content.ReadAsStringAsync();
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.BadRequest));
Assert.That(content, Is.EqualTo("\"Bad job\""));
}
}
After porting to v2, my function project csproj
file looks like this. The only differences are that I'm no longer targeting full framework, and the addition of the AzureFunctionsVersion
node.
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<AzureFunctionsVersion>v2</AzureFunctionsVersion>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Sdk.Functions" Version="1.0.24" />
</ItemGroup>
</Project>
And this is the csproj
for my test project after retargeting to .NET Core 2.0
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp2.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="nunit" Version="3.11.0" />
<PackageReference Include="NUnit3TestAdapter" Version="3.13.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.9.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\FunctionExample\FunctionExample.csproj" />
</ItemGroup>
</Project>
Previously, I was using the answers to this question to properly stub out HttpRequestMessage but that no longer appears to work.
When I try to compile this, I get the following compilation errors
Error CS0246 The type or namespace name 'HttpConfiguration' could not be found (are you missing a using directive or an assembly reference?)
Error CS0103 The name 'HttpPropertyKeys' does not exist in the current context
So if I just remove the line, hoping that the fix is no longer needed
request.Properties.Add(HttpPropertyKeys.HttpConfigurationKey, new HttpConfiguration());
Instead I get this error message
System.InvalidOperationException : The HttpRequestMessage instance is not properly initialized. Use HttpRequestMessageHttpContextExtensions.GetHttpRequestMessage to create an HttpRequestMessage for the current request.
Trying to follow the error message's directions didn't prove fruitful to me, I tried to set the HttpContext
like was done in this question
request.Properties.Add(nameof(HttpContext), new DefaultHttpContext());
But that gave me a different error (same as in the question)
System.ArgumentNullException : Value cannot be null.
Parameter name: provider
Azure Functions is somewhat based on ASP.NET MVC WebApi, which has had some changes for .NET Core. HttpConfiguration
for example doesn't appear to be available in any packages that target .NET Core/Standard. In order to fix this, I had to install a couple of packages in my test project, namely Microsoft.AspNetCore.Mvc for AddMvc()
and Microsoft.AspNetCore.Mvc.WebApiCompatShim for .AddWebApiConventions()
, which:
Provides compatibility in ASP.NET Core MVC with ASP.NET Web API 2 to simplify migration of existing Web API implementations
So I added these to my test project
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.2.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.WebApiCompatShim" Version="2.2.0" />
and now my test project looks like this
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp2.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="nunit" Version="3.11.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.2.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.WebApiCompatShim" Version="2.2.0" />
<PackageReference Include="NUnit3TestAdapter" Version="3.13.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.9.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\FunctionExampleFunction\FunctionExampleFunction.csproj" />
</ItemGroup>
</Project>
To mock the services that the ArgumentNullException
was implying were missing (which in this case I think are MediaTypeFormatters), I had to essentially bootstrap MVC to get the HttpContext initialized properly.
[Test]
public async Task TestSomeFunction()
{
var request = new HttpRequestMessage
{
Method = HttpMethod.Post,
RequestUri = new Uri("http://localhost/"),
Content = new StringContent("", Encoding.UTF8, "application/json")
};
var services = new ServiceCollection()
.AddMvc()
.AddWebApiConventions()
.Services
.BuildServiceProvider();
request.Properties.Add(nameof(HttpContext), new DefaultHttpContext
{
RequestServices = services
});
var response = await FunctionExample.SomeFunction(request);
var content = await response.Content.ReadAsStringAsync();
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.BadRequest));
Assert.That(content, Is.EqualTo("\"Bad job\""));
}
And that makes the test compile, run, and pass.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With