首页 > 解决方案 > 如何在 ASP.Net Core 2.2 中对 CreatedAtAction 路由值进行单元测试以停止运行时失败

问题描述

在将我的 API 从 ASP.Net Core 2.1 升级到 2.2 后,我在运行时遇到了一些 InvalidOperationException 异常。

调用栈

System.InvalidOperationException:
   at Microsoft.AspNetCore.Mvc.CreatedAtActionResult.OnFormatting (Microsoft.AspNetCore.Mvc.Core, Version=2.2.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ObjectResultExecutor.ExecuteAsync (Microsoft.AspNetCore.Mvc.Core, Version=2.2.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60)
   at Microsoft.AspNetCore.Mvc.ObjectResult.ExecuteResultAsync (Microsoft.AspNetCore.Mvc.Core, Version=2.2.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60)
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker+<InvokeResultAsync>d__20.MoveNext (Microsoft.AspNetCore.Mvc.Core, Version=2.2.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60)

原因

这是由于我的 CreatedAtAction 中缺少参数而发生的。

public async Task<IActionResult> GetFields([FromRoute]Guid productId)
{
    return Ok(await _prodRepo.GetProductFields(productId));
}

public async Task<IActionResult> CreateFields([FromRoute]Guid productId, [FromBody]ProductField[] fields)
{
    ...
    return CreatedAtAction(nameof(GetFields), fields);
}

解析度

最后一行应该包含productId路由值,如下所示:

return CreatedAtAction(nameof(GetFields), { productId }, fields);

当路由值名称不匹配时,也会发生同样的错误。它在 2.1 中并没有导致运行时异常,但我猜对于任何依赖返回 URL 的人来说,它都会默默地失败。

更大的问题

如果路由值的命名不正确,则在运行时会发生相同的异常。代码编译时没有错误也没有警告,并且在运行时失败。

我担心的是,这些错误在开发过程中很容易引入容易遗漏,并且只会在运行时浮出水面。我们有一个开发人员团队积极致力于这个 Web API 项目。当一个动作方法的签名发生变化时,它会再次发生,从另一个动作的CreatedAtAction结果中引用。

我该如何对这个错误案例进行单元测试?我不想在部署之前在所有 API 端点上运行集成测试来捕获运行时错误。

试图

我尝试了以下方法,但后来发现我需要一个 UrlHelper 并在这一点上卡住了。

[Fact]
public void Test_CreateFields_CreatedAtAction_Values()
{
    var fields = new ProductFieldRel { ProductId = _productId };
    var task = _controller.CreateFields(_productId, new[] { fields });
    var result = task.Result as CreatedAtActionResult;

    Assert.NotNull(result);

    result.OnFormatting(new ControllerContext
    {
        HttpContext = new DefaultHttpContext { User = _user }
    });
}

标签: c#asp.net-web-apiasp.net-core

解决方案


推荐阅读