尝试使用UrlHelper测试控制器

时间:2019-01-15 12:41:58

标签: c# unit-testing xunit asp.net-core-mvc-2.0

尝试出于测试目的创建URLHelper会抛出NullReferenceException

示例:

[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);
}

每次运行此测试时,Url = new UrlHelper(new ActionContext())中引发的异常是:

Exception.Message:

  

消息:System.NullReferenceException:对象引用未设置为   对象的实例。

Exception.StackTrace:

  

UrlHelperBase.ctor(ActionContext actionContext)   ControllerUnitTest.AuthenticateAsyncTest()

使用:

  

xUnit 2.4.1,   Microsoft.NETCore.App 2.2.0,   Microsoft.AspNetCore.Routing.Abstractions 2.2.0

要重新创建异常:

  1. 创建一个空的MVC core 2.2解决方案
  2. 创建一个xunit测试项目
  3. 安装NuGet Microsoft.AspNetCore.Mvc.Core 2.2.0
  4. 在测试中编写:var Url = new UrlHelper(new ActionContext());
  5. 运行测试

应如下所示:

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());
        }
    }
}

我的问题:

  1. 是否有错误,或者为什么不起作用?
  2. 了解替代方法或链接的文献吗?

2 个答案:

答案 0 :(得分:3)

根据异常消息引用的GitHub source code

protected UrlHelperBase(ActionContext actionContext)
{
    if (actionContext == null)
    {
        throw new ArgumentNullException(nameof(actionContext));
    }

    ActionContext = actionContext;
    AmbientValues = actionContext.RouteData.Values;
    _routeValueDictionary = new RouteValueDictionary();
}

助手正在尝试访问原始示例中未提供的actionContext.RouteData.Values

提供必要的依赖关系,以使测试顺利完成。

[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);
}

还避免对单元测试使用异步void。请改用Task

答案 1 :(得分:0)

第二个选项是使用特定的构造函数。该文档指出应将其用于单元测试,更具体地说,当仅需要传入ActionContext而不由使用代码使用时,即可使用它。

UrlHelper Url = new UrlHelper(new ActionContext { RouteData = new RouteData() });

感谢navelDirt和pranavkm,他们在githhub上播放了: https://github.com/aspnet/AspNetCore/issues/6703