【问题标题】:Trying to Test a Controller with a UrlHelper尝试使用 UrlHelper 测试控制器
【发布时间】:2019-01-15 12:41:57
【问题描述】:

尝试创建 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()) 中抛出的异常是:

异常消息:

消息: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 核心 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. 感谢提供解决方法或链接的文献?

【问题讨论】:

  • ActionContext 很可能缺少一些分配依赖项
  • Url 是 Controller 的属性。 new Controller() { Url = something }; AKA 对象初始化器。
  • 你需要一个真正的帮手,还是仅仅嘲笑它就可以逃脱?
  • minimal reproducible example 中显示您实际尝试实现的目标,清楚地显示正在测试的代码。
  • @SyntaxError Url 是名称,因为这是一个初始化新类,您只需在类中设置变量即可。这就是为什么您需要 {} 并使用 no ;最后在那里。它是一个公共 IUrlHelper Url { get;放; }

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


【解决方案1】:

根据异常消息所指的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);
}

还要避免在单元测试中使用 async void。请改用Task

【讨论】:

  • 非常感谢您,这似乎可以解决问题。但我对 for Url = new UrlHelper (new ActionContext ()); 感到困惑。不起作用,因为 ActionContext() 的描述是:“摘要:创建一个空的 Microsoft.AspNetCore.Mvc.ActionContext。备注:提供默认构造函数仅用于单元测试目的。”
  • 根据source code默认构造函数只设置模型状态。其他一切都是默认的。
  • 我认为它应该可以工作,因为它在 MVC 核心 1.1 中工作。再次感谢您的帮助。
【解决方案2】:

第二种选择是使用特定的构造函数。该文档声明它应该用于单元测试,更具体地说,当 ActionContext 只需要传入,但不被消费代码使用时。

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

感谢在 githhub 上重播的 navelDirt 和 pranavkm: https://github.com/aspnet/AspNetCore/issues/6703

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-08-22
    • 2019-06-21
    • 1970-01-01
    • 2011-03-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多