Unit Test and Mock Sync/Async Controller Methods in ASP.NET Core

Unit Test and Mock SyncAsync Controller Methods in ASPNET Core

Today in this article, we will see how to Unit Test and Mock Sync/Async Controller Methods in ASP.NET Core.

Below is an example of the .NET Core unit testing sample for any controller method and their resolution using mocking.

Before we begin writing unit test cases for the controller, the first thing you should understand is that “Controller” is not special when it comes to unit testing.

Today in this article, we will cover below aspects,

The controller is simply a class like any other class which has members like methods and properties etc. The only thing we do a bit differently in controller unit testing is that of the REST response assertion.

Controller methods always return HTTP responses with resource details by following the REST principles.

We shall be using the same naming conventions for unit testing that we learned in our last article,

Asynchronous method

Here I am testing an async controller Method that also makes a call to an external service.

        [HttpGet]
        public async Task<IActionResult> GetAsync(string id)
        {
            Book book = null;
            try
            {
                //  await method - Asynchronously 
                book = await _bookService.GetAsync(id);
                if (book == null)
                {
                    return NotFound();
                }
                book.Price = 10;
            }
            catch(Exception ex)
            {
                throw;
            }

            // do more stuff

            return Ok(book);
        }

Asynchronous Controller – Mock and Unit Test

Below is an example of how we can write unit test cases for Asynchronous methods.

Here in the below example, I am following the same naming convention for Unit testing we learned in our last article.


Synchronous Controller Mock and Unit Test

Here below is an example of the Synchronous controller Method which also makes a call to an external service.

       [HttpGet]
        public ActionResult<Book> Get(string id)
        {
            var book = _bookService.Get(id);
            book.Price = 10; 
            if (book == null)
            {
                return NotFound();
            }
            return Ok(book);
        }

Resolution

Below is an example of how we can write unit test cases for Sync methods,

  
        [Fact]
        public void BookService_GetBookSync_With_ValidBookID()
        {

            //Arrange
            Book document = new Book()
            {
                Author = "The",
                BookName = "CodeBUzz",
                Id = "1234"
            };
            string bookID = "1234";
            var mockBookClient = new Mock<IBookService>();
            mockBookClient.Setup(c => c.Get(document.Id))
            .Returns(document);

            //Act
            BooksController service = new BooksController(mockBookClient.Object);
            var result = service.Get(bookID).Result as ObjectResult;
            var actualtResult = result.Value;

            //Assert
            //Return proper HTTPStatus code
            Assert.IsType<OkObjectResult>(result);
            //OR
            Assert.Equal(HttpStatusCode.OK, (HttpStatusCode)result.StatusCode);
            //Addtional asserts
            Assert.Equal(document.Author, ((Book)actualtResult).Author);
            Assert.Equal(document.BookName, ((Book)actualtResult).BookName);
            Assert.Equal(document.Id, ((Book)actualtResult).Id);


        }

Do you have any better suggestions to make our Controller methods more robust?


What to test in Controller Unit Testing?

Please note below a few helpful guidelines for Controller Unit testing.

  • Controller methods should be unit tested like any other regular methods.
  • Controller methods should be unit tested using assert for REST HTTP Status code.
  • Use HttpStatusCode enum to assert the actual result type.
    • Example 1

Assert.Equal(HttpStatusCode.OK, (HttpStatusCode)result.StatusCode);

  • Example 2

Assert.IsType<OkObjectResult>(result);

Above, either way, the Unit tests make our API robust and validate implementation for the REST principle.

Each controller method should be asserted for all possible types of HTTP status codes like 200, 401, 200, 500 status codes, etc. These assertions will assure that the Controller method produces proper results.

  • If the controller method is returning resources, such resources should be validated for their structure.
  • This will assure that the code follows a contract properly when the consumer consumes your API.
  • This schema assertion will red flag the code while development if there are any breaking changes.
  • Always assert if mocked methods are invoked at least once.
    • Example:

mockBookClient.Verify(c => c.GetAsync(It.IsAny()), Times.Once);

References:

Do you have any other better suggestions to test the method?

Please sound off your comments below!



Please bookmark this page and share it with your friends. Please Subscribe to the blog to receive notifications on freshly published(2024) best practices and guidelines for software design and development.



Leave a Reply

Your email address will not be published. Required fields are marked *