为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

C#
神不在的星期二 2021-10-24 17:16:10
我有一个 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?
查看完整描述

3 回答

?
互换的青春

TA贡献1797条经验 获得超6个赞

在运行时,由于隐式转换,您的原始测试代码仍然可以工作。


但是根据提供的调试器图像,测试似乎对结果的错误属性进行了断言。


因此,虽然更改被测方法允许测试通过,但无论哪种方式都可以实时运行


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)

{

    return new ActionResult<TValue>(result);

}

但是测试正在断言Value属性(参考 OP 中的图像),在这种情况下没有设置。


无需修改被测代码以满足测试,它可以访问该Result属性并对该值进行断言


[Fact]

public async Task GetLocationsCountAsync_WhenCalled_ReturnsLocationsCount() {

    //Arrange

    _locationsService

        .Setup(_ => _.GetLocationsCountAsync(It.IsAny<string>()))

        .ReturnsAsync(10);

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

        ControllerContext = { HttpContext = SetupHttpContext().Object }

    };


    //Act

    var actionResult = await controller.GetLocationsCountAsync();


    //Assert

    var result = actionResult.Result as OkObjectResult;

    result.Should().NotBeNull();

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


    VerifyAll();

}


查看完整回答
反对 回复 2021-10-24
?
忽然笑

TA贡献1806条经验 获得超5个赞

问题是将其包装在Ok. 如果返回对象本身,Value则填充正确。


如果您查看文档中的Microsoft 示例,他们只会将控制器方法用于非默认响应,例如NotFound:


[HttpGet("{id}")]

[ProducesResponseType(StatusCodes.Status404NotFound)]

public ActionResult<Product> GetById(int id)

{

    if (!_repository.TryGetProduct(id, out var product))

    {

        return NotFound();

    }


    return product;

}


查看完整回答
反对 回复 2021-10-24
  • 3 回答
  • 0 关注
  • 163 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信