Unit testing controller methods which return IActionResult

前端 未结 4 810
时光说笑
时光说笑 2020-12-05 09:07

I\'m in the process of building an ASP.NET Core WebAPI and I\'m attempting to write unit tests for the controllers. Most examples I\'ve found are from the older WebAPI/WebA

相关标签:
4条回答
  • Other answers adviced to cast to ObjectResult, but its work only if you return OkObjectResult \ NotFoundObjectResult \ etc. But server could return NotFound\ OkResult which derived from StatusCodeResult.

    For example:

    public class SampleController : ControllerBase
    {
        public async Task<IActionResult> FooAsync(int? id)
        {
            if (id == 0)
            {
                // returned "NotFoundResult" base type "StatusCodeResult"
                return NotFound();
            }
    
            if (id == 1)
            {
                // returned "StatusCodeResult" base type "StatusCodeResult"
                return StatusCode(StatusCodes.Status415UnsupportedMediaType);
            }
    
            // returned "OkObjectResult" base type "ObjectResult"
            return new OkObjectResult("some message");
        }
    }
    

    I looked at the implementation of all these methods and found that they are all inherited from the IStatusCodeActionResult interface. It seems like this is the most base type that contains StatusCode:

    private SampleController _sampleController = new SampleController();
    
    [Theory]
    [InlineData(0, StatusCodes.Status404NotFound)]
    [InlineData(1, StatusCodes.Status415UnsupportedMediaType)]
    [InlineData(2, StatusCodes.Status200OK)]
    public async Task Foo_ResponseTest(int id, int expectedCode)
    {
        var actionResult = await _sampleController.FooAsync(id);
        var statusCodeResult = (IStatusCodeActionResult)actionResult;
        Assert.Equal(expectedCode, statusCodeResult.StatusCode);
    }
    
    0 讨论(0)
  • 2020-12-05 09:50

    You can also do cool things like:

        var result = await controller.GetOrders();//
        var okResult = result as ObjectResult;
    
        // assert
        Assert.NotNull(okResult);
        Assert.True(okResult is OkObjectResult);
        Assert.IsType<TheTypeYouAreExpecting>(okResult.Value);
        Assert.Equal(StatusCodes.Status200OK, okResult.StatusCode);
    

    Thanks

    0 讨论(0)
  • 2020-12-05 09:54

    Assuming something like the

    public IActionResult GetOrders() {
        var orders = repository.All();
        return Ok(orders);
    }
    

    the controller in this case is returning an OkObjectResult class.

    Cast the result to the type of what you are returning in the method and perform your assert on that

    [Fact]
    public void GetOrders_WithOrdersInRepo_ReturnsOk() {
        // arrange
        var controller = new OrdersController(new MockRepository());
    
        // act
        var result = controller.GetOrders();
        var okResult = result as OkObjectResult;
    
        // assert
        Assert.IsNotNull(okResult);
        Assert.AreEqual(200, okResult.StatusCode);
    }
    
    0 讨论(0)
  • 2020-12-05 10:01

    You also can use ActionResult class as a controller result (assuming you have type Orders). In that case you can use something like this:

    [ProducesResponseType(typeof(Orders), StatusCodes.Status200OK)]
    public ActionResult<Orders> GetOrders()
    {
        return service.GetOrders();
    }
    

    and now in unit tests you have:

    Assert.IsInstanceOf<Orders>(result.Value);
    

    Besides, this is the recommendation of Microsoft - https://docs.microsoft.com/en-us/aspnet/core/web-api/action-return-types?view=aspnetcore-2.2#actionresultt-type

    Unfortunately, I don't know why using Ok method

    return Ok(service.GetOrders());
    

    doesn't map it properly.

    0 讨论(0)
提交回复
热议问题