Методы контроллера модульного тестирования, которые возвращают IActionResult
Я занимаюсь созданием ASP.NET Core WebAPI, и я пытаюсь написать модульные тесты для контроллеров. Большинство примеров, которые я нашел, относятся к более старым платформам WebAPI/WebAPI2 и, похоже, не коррелируют с новыми контроллерами Core.
Мои методы контроллера возвращают IActionResults
. Однако объект IActionResult
имеет только метод ExecuteResultAsync()
, который требует контекста контроллера. Я создаю экземпляр контроллера вручную, поэтому контекст контроллера в этом экземпляре имеет значение null, что вызывает исключение при вызове ExecuteResultAsync
. По сути, это приводит меня к очень хакерскому пути для успешного завершения этих модульных тестов и очень беспорядочно. Мне остается задаться вопросом, что должен быть более простой/правильный способ тестирования контроллеров API.
Кроме того, мои контроллеры НЕ используют async/await, если это имеет значение.
Простой пример того, чего я пытаюсь достичь:
Метод контроллера:
[HttpGet(Name = "GetOrdersRoute")]
public IActionResult GetOrders([FromQuery]int page = 0)
{
try
{
var query = _repository.GetAll().ToList();
int totalCount = query.Count;
int totalPages = (int)Math.Ceiling((double)totalCount / pageSize) - 1;
var orders = query.Skip(pageSize * page).Take(pageSize);
return Ok(new
{
TotalCount = totalCount,
TotalPages = totalPages,
Orders = orders
});
}
catch (Exception ex)
{
return BadRequest(ex);
}
}
Unit test:
[Fact]
public void GetOrders_WithOrdersInRepo_ReturnsOk()
{
// arrange
var controller = new OrdersController(new MockRepository());
// act
IActionResult result = controller.GetOrders();
// assert
Assert.Equal(HttpStatusCode.OK, ????);
}
Ответы
Ответ 1
Предполагая что-то вроде
public IActionResult GetOrders() {
var orders = repository.All();
return Ok(orders);
}
контроллер в этом случае возвращает класс OkObjectResult
.
Приведите результат к типу того, что вы возвращаете в методе, и подтвердите это.
[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);
}
Ответ 2
Вы также можете делать классные вещи, такие как:
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);
Спасибо
Ответ 3
Вы также можете использовать класс ActionResult в качестве результата контроллера (при условии, что у вас есть тип Orders).
В этом случае вы можете использовать что-то вроде этого:
[ProducesResponseType(typeof(Orders), StatusCodes.Status200OK)]
public ActionResult<Orders> GetOrders()
{
return service.GetOrders();
}
и теперь в модульных тестах у вас есть:
Assert.IsInstanceOf<Orders>(result.Value);
Кроме того, это рекомендация Microsoft - https://docs.microsoft.com/en-us/aspnet/core/web-api/action-return-types?view=aspnetcore-2.2#actionresultt-type
К сожалению, я не знаю, почему с помощью метода Ok
return Ok(service.GetOrders());
не отображает это должным образом.