我有一个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()));
}
结果的值是null,导致我的测试失败,但是如果您查看ActionResult.Result.Value
(一个内部属性),它包含预期的解析后的值。
请参见下面的调试器屏幕截图。
如何在单元测试中填充actionResult.Value?
发布于 2018-07-24 10:13:51
在运行时,由于隐式转换,测试中的原始代码仍然有效。
但是根据提供的调试器图像,看起来测试是在错误的结果属性上断言的。
因此,虽然更改测试下的方法可以使测试通过,但无论以哪种方式运行,它都可以正常工作
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();
}
发布于 2019-06-23 23:55:14
问题是把它包装在Ok
中。如果返回对象本身,则会正确填充Value
。
如果您查看Microsoft's examples in the docs,您会发现它们只对NotFound
等非默认响应使用控制器方法
[HttpGet("{id}")]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public ActionResult<Product> GetById(int id)
{
if (!_repository.TryGetProduct(id, out var product))
{
return NotFound();
}
return product;
}
发布于 2020-08-02 23:11:43
问题出在ActionResult<T>
令人困惑的接口上,这个接口从来没有设计成供我们人类使用。正如在其他答案中所述,ActionResult<T>
设置了Result
或Value
属性,但不能同时设置这两个属性。当您返回一个OkObjectResult
时,框架会填充Result
属性。当您返回一个对象时,框架会填充Value
属性。
我为我的测试库创建了以下简单的帮助器,以帮助我在使用OkObjectResult Ok()
或其他从ObjectResult
继承的结果时测试返回值
private static T GetObjectResultContent<T>(ActionResult<T> result)
{
return (T) ((ObjectResult) result.Result).Value;
}
这使我可以执行以下操作:
var actionResult = await controller.Get("foobar");
Assert.IsType<OkObjectResult>(actionResult.Result);
var resultObject = GetObjectResultContent<ObjectType>(actionResult);
Assert.Equal("foobar", resultObject.Id);
https://stackoverflow.com/questions/51489111
复制相似问题