问题
Trying to create a URLHelper
for testing purposes throws a NullReferenceException
.
Example:
[Fact]
public async void AuthenticateAsyncTest()
{
// Arrange
var controller = new Controller(serviceProvider)
{
Url = new UrlHelper(new ActionContext()) // Exception thrown
};
// Act
var result = await controller.Authenticate() as ViewResult;
// Assert
Assert.NotNull(result);
}
Every time I run this Test, the Exception that is thrown in Url = new UrlHelper(new ActionContext())
is:
Exception.Message:
Message: System.NullReferenceException : Object reference not set to an instance of an object.
Exception.StackTrace:
UrlHelperBase.ctor(ActionContext actionContext) ControllerUnitTest.AuthenticateAsyncTest()
Using:
xUnit 2.4.1, Microsoft.NETCore.App 2.2.0, Microsoft.AspNetCore.Routing.Abstractions 2.2.0
To recreate the Exception:
- Create a empty MVC core 2.2 solution
- Create a xunit test Project
- Install the NuGet Microsoft.AspNetCore.Mvc.Core 2.2.0
- Write in the test: var Url = new UrlHelper(new ActionContext());
- Run test
Should look like this:
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Routing;
using Xunit;
namespace XUnitTestProject1
{
public class UnitTest1
{
[Fact]
public void Test1()
{
var Url = new UrlHelper(new ActionContext());
}
}
}
My questions:
- Is there a bug, or why is this not working?
- Literature to a workaround or links are appreciated?
回答1:
According to GitHub source code referred to by the exception message,
protected UrlHelperBase(ActionContext actionContext)
{
if (actionContext == null)
{
throw new ArgumentNullException(nameof(actionContext));
}
ActionContext = actionContext;
AmbientValues = actionContext.RouteData.Values;
_routeValueDictionary = new RouteValueDictionary();
}
The helper is trying to access actionContext.RouteData.Values
which was not provided in the original example.
Provide the necessary dependencies for the test to flow to completion.
[Fact]
public async Task AuthenticateAsyncTest() {
// Arrange
var httpContext = new DefaultHttpContext();
var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor());
var controller = new Controller(serviceProvider) {
Url = new UrlHelper(actionContext)
};
// Act
var result = await controller.Authenticate() as ViewResult;
// Assert
Assert.NotNull(result);
}
Also avoid using async void for unit tests. Use Task
instead.
回答2:
The second option would be to use the specific constructor. The document states that it should be used for unit testing, more specifically when the ActionContext simply needs to be passed in, but not used by the consuming code.
UrlHelper Url = new UrlHelper(new ActionContext { RouteData = new RouteData() });
Thank you to navelDirt and pranavkm who replayed on githhub: https://github.com/aspnet/AspNetCore/issues/6703
来源:https://stackoverflow.com/questions/54199103/trying-to-test-a-controller-with-a-urlhelper