猿问

如何使用 ActionResult<T> 进行单元测试?

我有一个 xUnit 测试,如:


[Fact]

public async void GetLocationsCountAsync_WhenCalled_ReturnsLocationsCount()

{

    _locationsService.Setup(s => s.GetLocationsCountAsync("123")).ReturnsAsync(10);

    var controller = new LocationsController(_locationsService.Object, null)

    {

        ControllerContext = { HttpContext = SetupHttpContext().Object }

    };

    var actionResult = await controller.GetLocationsCountAsync();

    actionResult.Value.Should().Be(10);

    VerifyAll();

}

来源是


/// <summary>

/// Get the current number of locations for a user.

/// </summary>

/// <returns>A <see cref="int"></see>.</returns>

/// <response code="200">The current number of locations.</response>

[HttpGet]

[Route("count")]

public async Task<ActionResult<int>> GetLocationsCountAsync()

{

    return Ok(await _locations.GetLocationsCountAsync(User.APropertyOfTheUser()));

}

结果的值为空,导致我的测试失败,但如果您查看ActionResult.Result.Value(内部属性),它包含预期的解析值。


请参阅以下调试器的屏幕截图。

如何在单元测试中填充 actionResult.Value?


神不在的星期二
浏览 164回答 3
3回答

互换的青春

在运行时,由于隐式转换,您的原始测试代码仍然可以工作。但是根据提供的调试器图像,测试似乎对结果的错误属性进行了断言。因此,虽然更改被测方法允许测试通过,但无论哪种方式都可以实时运行ActioResult<TValue> 有两个属性,根据使用它的操作返回的内容进行设置。/// <summary>/// Gets the <see cref="ActionResult"/>./// </summary>public ActionResult Result { get; }/// <summary>/// Gets the value./// </summary>public TValue Value { get; }来源因此,当使用Ok()它返回的控制器操作将ActionResult<int>.Result通过隐式转换设置操作结果的属性。public static implicit operator ActionResult<TValue>(ActionResult result){&nbsp; &nbsp; return new ActionResult<TValue>(result);}但是测试正在断言Value属性(参考 OP 中的图像),在这种情况下没有设置。无需修改被测代码以满足测试,它可以访问该Result属性并对该值进行断言[Fact]public async Task GetLocationsCountAsync_WhenCalled_ReturnsLocationsCount() {&nbsp; &nbsp; //Arrange&nbsp; &nbsp; _locationsService&nbsp; &nbsp; &nbsp; &nbsp; .Setup(_ => _.GetLocationsCountAsync(It.IsAny<string>()))&nbsp; &nbsp; &nbsp; &nbsp; .ReturnsAsync(10);&nbsp; &nbsp; var controller = new LocationsController(_locationsService.Object, null) {&nbsp; &nbsp; &nbsp; &nbsp; ControllerContext = { HttpContext = SetupHttpContext().Object }&nbsp; &nbsp; };&nbsp; &nbsp; //Act&nbsp; &nbsp; var actionResult = await controller.GetLocationsCountAsync();&nbsp; &nbsp; //Assert&nbsp; &nbsp; var result = actionResult.Result as OkObjectResult;&nbsp; &nbsp; result.Should().NotBeNull();&nbsp; &nbsp; result.Value.Should().Be(10);&nbsp; &nbsp; VerifyAll();}

忽然笑

问题是将其包装在Ok. 如果返回对象本身,Value则填充正确。如果您查看文档中的Microsoft 示例,他们只会将控制器方法用于非默认响应,例如NotFound:[HttpGet("{id}")][ProducesResponseType(StatusCodes.Status404NotFound)]public ActionResult<Product> GetById(int id){&nbsp; &nbsp; if (!_repository.TryGetProduct(id, out var product))&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; return NotFound();&nbsp; &nbsp; }&nbsp; &nbsp; return product;}
随时随地看视频慕课网APP
我要回答