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/WebAPI2 platforms and don't seem to correlate with the new Core controllers.
My controller methods are returning IActionResults
. However, the IActionResult
object only has a ExecuteResultAsync()
method which requires a controller context. I'm instantiating the controller manually, so the controller context in this instance is null, which causes an exception when calling ExecuteResultAsync
. Essentially this is leading me down a very hacky path to get these unit tests to successfully complete and is very messy. I'm left wondering that there must be a more simple/correct way of testing API controllers.
Also, my controllers are NOT using async/await if that makes a difference.
Simple example of what I'm trying to achieve:
Controller method:
[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, ????); }
The IActionResult return type is appropriate when multiple ActionResult return types are possible in an action. The ActionResult types represent various HTTP status codes. Any non-abstract class deriving from ActionResult qualifies as a valid return type.
Yeah I think it does. The unit tests will test individual functionality and also provide you with a means to test if the unit was broken when other code changed. The integration test then tests the end-to-end process.
First we need to add an employee class in the Models folder. Following is the Employee class implementation. We need to add EmployeeController. Right-click on the controller folder in the solution explorer and select Add → Controller.
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); }
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With