如何使用返回类型 ActionResult 对操作进行单元测试?

2024-01-06

我的问题与这个非常相似:

当返回类型为 ActionResult 时,如何对操作进行单元测试? https://stackoverflow.com/q/18865257/419956

问题是我的问题混合在generic ActionResult<T> type, async, and Ok(...)。我似乎无法使链接问题的答案适应一般情况。或者我的情况可能略有不同。

这是一个复制品。创建“API”类型的新 ASP.NET Core Web 应用程序。将新的 xUnit .NET Core 测试项目添加到解决方案,该项目引用 API 项目(以及任何所需的框架库)。分别创建控制器和测试,如下所示:

public class Thing { public string Name => "Foobar"; }
[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
    [HttpGet]
    public async Task<ActionResult<Thing>> Get()
    {
        // The real "Thing" would be asynchronously retrieved from the DB
        return Ok(new Thing());
    }
}
[Fact]
public async Task Test1()
{
    var controller = new ValuesController();
    var actionResult = await controller.Get();
    Assert.NotNull(actionResult.Value);
    Assert.Equal("Foobar", actionResult.Value.Name);
}

该测试没有变绿,而是失败on the NotNull断言(或者,如果我没有这个断言,它会抛出一个NullReferenceException).

在调试和检查类层次结构之后,我发现这似乎给出了预期的结果:

[Fact]
public async Task Test1()
{
    var controller = new ValuesController();
    var actionResult = await controller.Get();
    var okResult = actionResult.Result as OkObjectResult;
    var realResult = okResult?.Value as Thing;
    Assert.Equal("Foobar", realResult?.Name);
}

但这感觉就像我做错了什么。实际上,我留下了两个相关的问题:

  1. 是否有另一种惯用的方式来编写这个测试,从而崩溃所有这些as casts?
  2. 为什么第一个示例可以编译,但却给出运行时异常?这里发生了什么?

通过 XUnit,您可以使用T t = Assert.IsType<T>(other)。如果可能的话,这将进行转换,但否则将导致测试失败。

例如我做这样的事情:

IActionResult actionResult = await Controller.GetItem(id);
OkObjectResult okObjectResult = Assert.IsType<OkObjectResult>(actionResult);
Model model = Assert.IsType<Model>(okObjectResult.Value);
Assert.Equal(id, model.Id);

至于你的第二个问题,事情可以在运行时抛出空引用异常并正确编译。这个问题将通过 C# 8 和不可空类型来解决。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何使用返回类型 ActionResult 对操作进行单元测试? 的相关文章

随机推荐