如何测试返回Ok(object)的ASP.NET Core 2.2 Web API GET IActionResult?

5

在我的Web API中,我有一个简单的控制器动作:

[HttpGet]
[Route("[action]")]
public IActionResult GetApiStatus(string token)
{
    if (_token != token)
    {
        return StatusCode(401);
    }

    StatusModel status = _vesselUpdating.GetUpdatingStatus();

    return Ok(status);
}

这个操作返回StatusModel类型的对象。我无法管理如何测试它的返回状态。

我的测试方法如下:

[Theory]
[InlineData("wrong_token", StatusCodes.Status401Unauthorized)]
[InlineData("test_token", StatusCodes.Status200OK)]
[InlineData("", StatusCodes.Status401Unauthorized)]
[InlineData(null, StatusCodes.Status401Unauthorized)]
public void Get_GetAnyAction_WithVariusTokens_ReturnsCorrectStatusCode(string token, int code)
{
    _vesselUpdatingMock.Setup(v => v.GetUpdatingStatus()).Returns(_sampleStatusModel);
    IActionResult result;

    result = _updatesController.GetApiStatus(token);
    StatusCodeResult resultGetApiStatus = result as StatusCodeResult;

    Assert.Equal(code, resultGetApiStatus.StatusCode);
}

在调试时。
result = _updatesController.GetApiStatus(token);

IActionResultStatusCode 属性为 200,但其中的 DeclaredType 属性却为 null

result debug

在进行断言时,最终我在resultGetApiStatus中得到了null

assert null

我没有找到类似的例子。如何正确投影result重要编辑: 我只找到了this approach,它不能解决我的问题,因为有多种情况涉及[Theory],而且不是所有其他操作都返回ObjectResult,其中一些仅返回StatusCode。是否有适用于具有和不具有ObjectResult的操作的通用方法?还是应该使用不同的测试?
2个回答

2

这是您不独有的挫败感。

OkObjectResult并未继承自StatusCodeResult,因此

StatusCodeResult resultGetApiStatus = result as StatusCodeResult;

正确地返回了 null。

参见:https://github.com/aspnet/Mvc/issues/7134

您应该能够强制转换为 IStatusCodeActionResult

https://github.com/dotnet/aspnetcore/blob/a410ed460140a55dd699e83d978b798de48802fb/src/Mvc/Mvc.Core/src/StatusCodeResult.cs#L32 然而,我不确定这个版本是哪个(2.1?)

[Theory]
[InlineData("wrong_token", StatusCodes.Status401Unauthorized)]
[InlineData("test_token", StatusCodes.Status200OK)]
[InlineData("", StatusCodes.Status401Unauthorized)]
[InlineData(null, StatusCodes.Status401Unauthorized)]
public void Get_GetAnyAction_WithVariusTokens_ReturnsCorrectStatusCode(string token, int code)
{
    _vesselUpdatingMock.Setup(v => v.GetUpdatingStatus()).Returns(_sampleStatusModel);

    var result = _updatesController.GetApiStatus(token);
    var resultGetApiStatus = result as IStatusCodeActionResult;

    Assert.Equal(code, resultGetApiStatus.StatusCode);
}

1
根据文档,它是在2.2中添加的,因此基于OP在标题中指定的版本仍然有效。 - Nkosi
我找的就是“IStatusCodeActionResult” :) - bakunet

2

测试逻辑有缺陷,这也导致了根据所提供的输入应用于测试对象而产生混合结果。

基于期望行为进行特定结果的测试,允许在测试对象中测试一个逻辑路径。

例如:

[Theory]
[InlineData("wrong_token")]
[InlineData("")]
[InlineData(null)]
public void Get_GetAnyAction_WithInvalidTokens_ReturnsUnauthorizedStatusCode(string token) {
    //Arrange
    int expected = StatusCodes.Status401Unauthorized;

    //Act
    StatusCodeResult result = _updatesController.GetApiStatus(token) as StatusCodeResult;

    //Assert
    int actual = result.StatusCode;
    Assert.Equal(expected, actual);
}

[Fact]
public void Get_GetAnyAction_WithValidToken_ReturnsCorrectStatusCode() {
    //Arrange
    _vesselUpdatingMock.Setup(v => v.GetUpdatingStatus()).Returns(_sampleStatusModel);
    string token = "test_token";

    //Act
    OkObjectResult result = _updatesController.GetApiStatus(token) as OkObjectResult;

    //Assert
    int expected = StatusCodes.Status200OK;
    int actual = result.StatusCode;
    Assert.Equal(expected, actual);
}

那样做可以避免在测试中添加条件逻辑,这意味着测试功能过多。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接