Trying to Test a Controller with a UrlHelper

▼魔方 西西 提交于 2021-02-16 18:07:17

问题


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:

  1. Create a empty MVC core 2.2 solution
  2. Create a xunit test Project
  3. Install the NuGet Microsoft.AspNetCore.Mvc.Core 2.2.0
  4. Write in the test: var Url = new UrlHelper(new ActionContext());
  5. 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:

  1. Is there a bug, or why is this not working?
  2. 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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!