How to Set Up Unit Testing for ASP.NET MVC Web API Controllers

Photo by Steve Johnson on Unsplash

Introduction

This article gets you started testing ASP.NET MVC Web API controllers with a single API endpoint test.

This is a basic tutorial that tests a Get request only— in later articles, I will discuss how to test that the correct attributes are applied to the controller methods, as well as how to test async controllers.

Setup

Create a new MVC Web API solution called Shop.

Add the Domain Model

To this solution, add a new project called Shop.DomainModel and add a class called Product. For the scope of this demo, we will not add properties to this class.

namespace Shop.DomainModel
{
public class Product
{
}
}

Add a Services Project

Next, add another project called Shop.Services and to that add an interface called IProductService and make sure you add a project reference to Shop.DomainModel.

Inside of IProductService, add a parameterless method called GetProducts for the contract that will return a collection of all products.

using System.Collections.Generic;
using Shop.DomainModel;
namespace Shop.Services
{
public interface IProductService
{
IEnumerable<Product> GetProducts();
}
}

We can skip adding concrete implementation in a ProductService class as only the interface will be mocked later in the controller unit test.

Add an API Controller

Add a controller called ProductController in the Shop project, and include project references to Shop.DomainModel and Shop.Services.

Add a constructor that injects the product service and add one parameterless method called Get, which returns a collection of Product objects as shown below

using System.Collections.Generic;
using Microsoft.AspNetCore.Mvc;
using Shop.DomainModel;
using Shop.Services;
namespace Shop.Controllers
{
public class ProductController : Controller
{
private readonly IProductService _productService;
public ProductController(IProductService productService)
{
_productService = productService;
}
// GET: api/product
[HttpGet]
public IEnumerable<Product> Get()
{
return null;
}
}
}

Return null for the moment — we will come back to this once we’ve written tests for this.

Create a Controller Test Project

Create a test project for the controllers called Shop.Tests and add a test controller class called ProductControllerTests. Make sure you’ve got references to Shop, Shop.DomainModel and Shop.Services.

You will also need to add a NuGet package Moq:

Now mock the product service as follows:

using Moq;
using NUnit.Framework;
using Shop.Services;
namespace Shop.Tests
{
public class Tests
{
private Mock<IProductService> _mockProductService;
private ProductController _productController;
[SetUp]
public void Setup()
{
_mockProductService = new Mock<IProductService>();
_productController = new ProductController(_mockProductService.Object);
}
}
}

Let’s create a test to check that the Get controller method returns a collection of products from a mocked product service.

We need to set up the mock product service to return a collection of products and verify the

using System.Collections.Generic;
using Moq;
using NUnit.Framework;
using Shop.Controllers;
using Shop.DomainModel;
using Shop.Services;
namespace Shop.Tests
{
[TestFixture]
public class Tests
{
private Mock<IProductService> _mockProductService;
private ProductController _productController;
[SetUp]
public void Setup()
{
_mockProductService = new Mock<IProductService>();
_productController = new ProductController(_mockProductService.Object);
}
[Test]
public void Get_Should_Return_Products()
{
// arrange
var products = new List<Product>
{
new Product()
};
_mockProductService
.Setup(x => x.GetProducts())
.Returns(products);
// act
var result = _productController.Get();
// assert
Assert.AreEqual(products, result);
_mockProductService
.Verify(x => x.GetProducts(), Times.Once);
}
}
}

Run the test to show that it fails, since we haven’t provided any proper implementation yet for the controller method Get.

Now return to the ProductController and provide an implementation for the API method, calling the service method:

using System.Collections.Generic;
using Microsoft.AspNetCore.Mvc;
using Shop.DomainModel;
using Shop.Services;
namespace Shop.Controllers
{
public class ProductController : Controller
{
private readonly IProductService _productService;
public ProductController(IProductService productService)
{
_productService = productService;
}
// GET: api/product
[HttpGet]
public IEnumerable<Product> Get()
{
return _productService.GetProducts();
}
}
}

Re-run the test and show that it passes.

Note

For testing a real API call you’ll need to implement the IProductService interface in a concrete class, ProductService, and register the service in the Startup.cs file:

public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddScoped<IProductService, ProductService>();
}

Thanks for reading! Let me know what you think in the comments section below, and don’t forget to subscribe. 👍

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
George Marklow

George Marklow

George is a software engineer, author, blogger, and abstract artist who believes in helping others to make us happier and healthier.