4

In my Web API I have a simple controller action:

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

    StatusModel status = _vesselUpdating.GetUpdatingStatus();

    return Ok(status);
}

And action returns StatusModel type object. I could not manage how to test its return status.

My test method is below:

[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);
}

When debugging on

result = _updatesController.GetApiStatus(token);

the StatusCode property of IActionResult is 200, but only DeclaredType property of that is null.

result debug

And when Asserting, at the end I have in my resultGetApiStatus null.

assert null

I did not managed to find similar example. How can I project result properly?

IMPORTANT EDIT:

I found only this approach, that does not fix my problem, regarding variety of cases [Theory], and not all my other actions returns ObjectResult, some of them return only StatusCode. Is there any universal approach for actions with and without ObjectResult? Or should I use different tests?

Nkosi
  • 191,971
  • 29
  • 311
  • 378
bakunet
  • 191
  • 10

2 Answers2

2

A frustration not only you possess.

OkObjectResult does not inherit from StatusCodeResult, ergo

StatusCodeResult resultGetApiStatus = result as StatusCodeResult;

Is rightly returning null.

See: https://github.com/aspnet/Mvc/issues/7134

You should be able to coerce to an IStatusCodeActionResult

https://github.com/dotnet/aspnetcore/blob/a410ed460140a55dd699e83d978b798de48802fb/src/Mvc/Mvc.Core/src/StatusCodeResult.cs#L32 however, I'm unsure which version this shipped with (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);
}
Nkosi
  • 191,971
  • 29
  • 311
  • 378
Mardoxx
  • 3,964
  • 5
  • 33
  • 57
2

The testing logic is flawed, which also leads to mixed outcomes based on the provided inputs applied to the subject under test.

Test for specific outcomes based on the expected behavior that allow for one logical path to be tested in the subject.

For example

[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);
}

That way you avoid having to add conditional logic to the test which would mean the test is doing too much

Nkosi
  • 191,971
  • 29
  • 311
  • 378