Unit Testing ASP.NET Web API 2
This guidance and application demonstrate how to create simple unit tests for your Web API 2 application. This tutorial shows how to include a unit test project in your solution, and write test methods that check the returned values from a controller method.
This tutorial assumes you are familiar with the basic concepts of ASP.NET Web API. For an introductory tutorial, see Getting Started with ASP.NET Web API 2.
The unit tests in this topic are intentionally limited to simple data scenarios. For unit testing more advanced data scenarios, see Mocking Entity Framework when Unit Testing ASP.NET Web API 2.
Software versions used in the tutorial
- Visual Studio 2017
- Web API 2
In this topic
This topic contains the following sections:
- Prerequisites
- Download code
- Set up the Web API 2 application
- Install NuGet packages in test project
- Create tests
Visual Studio 2017 Community, Professional or Enterprise edition
Download the completed project. The downloadable project includes unit test code for this topic and for the Mocking Entity Framework when Unit Testing ASP.NET Web API topic.
## Create application with unit test project
You can either create a unit test project when creating your application or add a unit test project to an existing application. This tutorial shows both methods for creating a unit test project. To follow this tutorial, you can use either approach.
### Add unit test project when creating the application
Create a new ASP.NET Web Application named StoreApp.
In the New ASP.NET Project windows, select the Empty template and add folders and core references for Web API. Select the Add unit tests option. The unit test project is automatically named StoreApp.Tests. You can keep this name.
After creating the application, you will see it contains two projects.
### Add unit test project to an existing application
If you did not create the unit test project when you created your application, you can add one at any time. For example, suppose you already have an application named StoreApp, and you want to add unit tests. To add a unit test project, right-click your solution and select Add and New Project.
Select Test in the left pane, and select Unit Test Project for the project type. Name the project StoreApp.Tests.
You will see the unit test project in your solution.
In the unit test project, add a project reference to the original project.
## Set up the Web API 2 application
In your StoreApp project, add a class file to the Models folder named Product.cs. Replace the contents of the file with the following code.
[!code-csharpMain]
1: using System;
2:
3: namespace StoreApp.Models
4: {
5: public class Product
6: {
7: public int Id { get; set; }
8: public string Name { get; set; }
9: public decimal Price { get; set; }
10: }
11: }
Build the solution.
Right-click the Controllers folder and select Add and New Scaffolded Item. Select Web API 2 Controller - Empty.
Set the controller name to SimpleProductController, and click Add.
Replace the existing code with the following code. To simplify this example, the data is stored in a list rather than a database. The list defined in this class represents the production data. Notice that the controller includes a constructor that takes as a parameter a list of Product objects. This constructor enables you to pass test data when unit testing. The controller also includes two async methods to illustrate unit testing asynchronous methods. These async methods were implemented by calling Task.FromResult to minimize extraneous code, but normally the methods would include resource-intensive operations.
[!code-csharpMain]
1: using System;
2: using System.Collections.Generic;
3: using System.Linq;
4: using System.Threading.Tasks;
5: using System.Web.Http;
6: using StoreApp.Models;
7:
8: namespace StoreApp.Controllers
9: {
10: public class SimpleProductController : ApiController
11: {
12: List<Product> products = new List<Product>();
13:
14: public SimpleProductController() { }
15:
16: public SimpleProductController(List<Product> products)
17: {
18: this.products = products;
19: }
20:
21: public IEnumerable<Product> GetAllProducts()
22: {
23: return products;
24: }
25:
26: public async Task<IEnumerable<Product>> GetAllProductsAsync()
27: {
28: return await Task.FromResult(GetAllProducts());
29: }
30:
31: public IHttpActionResult GetProduct(int id)
32: {
33: var product = products.FirstOrDefault((p) => p.Id == id);
34: if (product == null)
35: {
36: return NotFound();
37: }
38: return Ok(product);
39: }
40:
41: public async Task<IHttpActionResult> GetProductAsync(int id)
42: {
43: return await Task.FromResult(GetProduct(id));
44: }
45: }
46: }
The GetProduct method returns an instance of the IHttpActionResult interface. IHttpActionResult is one of the new features in Web API 2, and it simplifies unit test development. Classes that implement the IHttpActionResult interface are found in the System.Web.Http.Results namespace. These classes represent possible responses from an action request, and they correspond to HTTP status codes.
Build the solution.
You are now ready to set up the test project.
## Install NuGet packages in test project
When you use the Empty template to create an application, the unit test project (StoreApp.Tests) does not include any installed NuGet packages. Other templates, such as the Web API template, include some NuGet packages in the unit test project. For this tutorial, you must include the Microsoft ASP.NET Web API 2 Core package to the test project.
Right-click the StoreApp.Tests project and select Manage NuGet Packages. You must select the StoreApp.Tests project to add the packages to that project.
Find and install Microsoft ASP.NET Web API 2 Core package.
Close the Manage NuGet Packages window.
By default, your test project includes an empty test file named UnitTest1.cs. This file shows the attributes you use to create test methods. For your unit tests, you can either use this file or create your own file.
For this tutorial, you will create your own test class. You can delete the UnitTest1.cs file. Add a class named TestSimpleProductController.cs, and replace the code with the following code.
[!code-csharpMain]
1: using System;
2: using System.Collections.Generic;
3: using System.Threading.Tasks;
4: using System.Web.Http.Results;
5: using Microsoft.VisualStudio.TestTools.UnitTesting;
6: using StoreApp.Controllers;
7: using StoreApp.Models;
8:
9: namespace StoreApp.Tests
10: {
11: [TestClass]
12: public class TestSimpleProductController
13: {
14: [TestMethod]
15: public void GetAllProducts_ShouldReturnAllProducts()
16: {
17: var testProducts = GetTestProducts();
18: var controller = new SimpleProductController(testProducts);
19:
20: var result = controller.GetAllProducts() as List<Product>;
21: Assert.AreEqual(testProducts.Count, result.Count);
22: }
23:
24: [TestMethod]
25: public async Task GetAllProductsAsync_ShouldReturnAllProducts()
26: {
27: var testProducts = GetTestProducts();
28: var controller = new SimpleProductController(testProducts);
29:
30: var result = await controller.GetAllProductsAsync() as List<Product>;
31: Assert.AreEqual(testProducts.Count, result.Count);
32: }
33:
34: [TestMethod]
35: public void GetProduct_ShouldReturnCorrectProduct()
36: {
37: var testProducts = GetTestProducts();
38: var controller = new SimpleProductController(testProducts);
39:
40: var result = controller.GetProduct(4) as OkNegotiatedContentResult<Product>;
41: Assert.IsNotNull(result);
42: Assert.AreEqual(testProducts[3].Name, result.Content.Name);
43: }
44:
45: [TestMethod]
46: public async Task GetProductAsync_ShouldReturnCorrectProduct()
47: {
48: var testProducts = GetTestProducts();
49: var controller = new SimpleProductController(testProducts);
50:
51: var result = await controller.GetProductAsync(4) as OkNegotiatedContentResult<Product>;
52: Assert.IsNotNull(result);
53: Assert.AreEqual(testProducts[3].Name, result.Content.Name);
54: }
55:
56: [TestMethod]
57: public void GetProduct_ShouldNotFindProduct()
58: {
59: var controller = new SimpleProductController(GetTestProducts());
60:
61: var result = controller.GetProduct(999);
62: Assert.IsInstanceOfType(result, typeof(NotFoundResult));
63: }
64:
65: private List<Product> GetTestProducts()
66: {
67: var testProducts = new List<Product>();
68: testProducts.Add(new Product { Id = 1, Name = "Demo1", Price = 1 });
69: testProducts.Add(new Product { Id = 2, Name = "Demo2", Price = 3.75M });
70: testProducts.Add(new Product { Id = 3, Name = "Demo3", Price = 16.99M });
71: testProducts.Add(new Product { Id = 4, Name = "Demo4", Price = 11.00M });
72:
73: return testProducts;
74: }
75: }
76: }
You are now ready to run the tests. All of the method that are marked with the TestMethod attribute will be tested. From the Test menu item, run the tests.
Open the Test Explorer window, and notice the results of the tests.
Summary
You have completed this tutorial. The data in this tutorial was intentionally simplified to focus on unit testing conditions. For unit testing more advanced data scenarios, see Mocking Entity Framework when Unit Testing ASP.NET Web API 2.
|