代码之家  ›  专栏  ›  技术社区  ›  Jeroen

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

  •  0
  • Jeroen  · 技术社区  · 6 年前

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

    How to unit-test an action, when return type is ActionResult?

    问题是我的问题混合在 通用 ActionResult<T> 类型, async Ok(...) . 我似乎无法将关联问题的答案与一般情况相适应。或者可能我的情况有点不同。

    这是一份复印件。创建“api”类型的新ASP.NET核心Web应用程序。向解决方案中添加一个新的XUnit.NET核心测试项目,该项目引用了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);
    }
    

    此测试没有变绿,而是失败 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 铸件?
    2. 为什么第一个示例编译,却给出了运行时异常?这是怎么回事?
    1 回复  |  直到 6 年前
        1
  •  1
  •   Daniel A. White    6 年前

    使用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和不可为空的类型来解决。