Creating Unit Tests for ASP.NET MVC Controllers

Dhananjay Kumar / Friday, January 15, 2016

In this blog post, we will learn to write unit tests for various MVC controller’s behaviors, such as view’s return types, redirecting to different actions etc. Specifically, we’ll cover writing Unit Tests for:

  1. ViewData of the Controller
  2. TempData of the Controller
  3. ViewBag of the Controller
  4. View of the Controller

Let’s get started!

Creating the MVC Project under Test

Let us go ahead and create a MVC project under Test. To keep things simpler, I have selected ”No Authentication” for the project. In this example we are going to write unit tests for the HomeController. The HomeController contains two action methods:

  1. Index
  2. Details

We are going to write tests for these actions. The HomeController contains code as shown here:

public class HomeController : Controller
    {
        public ActionResult Index()
        {
            return View("Index");
        }
        public ActionResult Details(string Id)
        {
            //logic to fetch details on ID
            return View("Details");
        }

    }

Creating the Test project

To create the Unit Test project, right click on the solution, and add a new Project. In the Add New Project dialog box, select Unit Test Project template from the Test tab as shown in the image below:

You can also create a Test Project while creating the MVC project, by selecting the checkbox to add Test Project. Once Test Project is created, right click on the project and add a reference to the MVC project. After it’s added, we need to add a reference of System.Web.Mvc in the test project by right clicking on the test project and selecting Manage Nuget Package. From the Nuget Package Manager, you can install Microsoft.AspNet.Mvc in the test project.

As a last step to setup the Test Project, right click and add a class named HomeControllerTest.  In the newly created class, write a sample test method as shown in the listing below.

public class HomeControllerTest
    {
 [TestMethod]
        public void SampleTest()
        {
            Assert.AreEqual("HomeController", "HomeController");
        }
    }

Now you’re ready to build the test project and you should not get any build errors. We have written the sample test method comparing two strings, and to run the test, simply select Test->Windows->Test Explorer as shown in the image below.

In the Test Explorer, you will find SampleTest listed there. To run the test, either right click on the test and select run, or click on the Run right on the top of the test. In this example we ran the SampleTest, which is passed! You can see Passed Tests in the Test Explorer as shown in the image below:

Now let’s go ahead and start writing tests for HomeController behaviors.

 Testing View returned by the Controller

Let us write test to verify whether the expected view is returned by the controller’s action method or not, and start by writing a test which will fail:

[TestMethod]
public void ReturnsDetailsView()
        {
          HomeController controllerUnderTest = new HomeController();
            var result = controllerUnderTest.Details("a1") as ViewResult;
            Assert.AreEqual("fooview", result.ViewName);
        }

As you see in the above test, we are calling Details action on the object of HomeController. The returned value of Details action is returned as ViewResult. In the last line, we’re asserting whether the name of the retuned view is equal to fooview or not. On running the test, we will get the error as shown below:

As you clearly find in the error message, the actual view name is Details. So let us go back and write the test to pass. To make the test pass, we changed the expected view name to Details.

[TestMethod]
        public void ReturnsDetailsView()
        {
            HomeController controllerUnderTest = new HomeController();
            var result = controllerUnderTest.Details("a1") as ViewResult;
            Assert.AreEqual("Details", result.ViewName);
        }

On running above test would pass.

Testing the ViewBag returned by the Controller

ViewBag, ViewData, and TempData are objects that pass data from one controllers to another controller or from the controller to the view as follows:

  1. ViewBag passes data from the Controller to the View
  2. ViewData passes data from the Controller to the View
  3. TempData passes data to subsequent HTTP request.

In the controller, ViewBag can be set as shown in the listing below:

  public ActionResult Details(string Id)
        {
            ViewBag.Name = "foo";
            //logic to fetch details on ID
            return View("Details");
        }

In the Details action, we are creating a Name property to the ViewBag, and setting its value to string foo.  The Unit Test to test the ViewBag can be written as shown in the listing below:

public void ReturnsViewBag()
        {
            HomeController controllerUnderTest = new HomeController();
            var result = controllerUnderTest.Details("a1") as ViewResult;
            Assert.AreEqual("foo", result.ViewData["Name"]);
           
        }

Simply, we are creating object of the controller and then calling the action. Typecasting the return value as ViewResult and then asserting the result. On running the test, we will find it has passed and the controller is returning the expected ViewBag.

Testing the ViewData returned by the Controller

In the controller, ViewData can be set as shown in the listing below:

public ActionResult Details(string Id)
        {
           
            ViewData["Name"] = "foo";
            //logic to fetch details on ID
            return View("Details");
        }

In the Details action, we are creating a ViewData, and setting its value to string foo.  The Unit Test to test ViewData can be written as shown in the listing below:

public void ReturnsViewData()
        {
            HomeController controllerUnderTest = new HomeController();
            var result = controllerUnderTest.Details("a1") as ViewResult;
            Assert.AreEqual("foo", result.ViewData["Name"]);

        }

Simply, we are creating an object of the controller and then calling the action. Typecasting the return value as ViewResult and then asserting the result. On running the test, we will find the test is passed and the controller is returning the expected ViewData.

Testing the TempData returned by the Controller

TempData is used to pass data to the next HTTP request. In simpler words, we can pass data from one controller/action to another controller/action using TempData. It can be set as shown in the listing below:

public ActionResult Details(string Id)
        {
           
            TempData["Name"] = "foo";
            //logic to fetch details on ID
           return RedirectToAction("Index");
        }

In the Details action, we are creating a TempData, and setting its value to string foo and redirecting to the Index action. The Unit Test to test TempData can be written as shown:

[TestMethod]
        public void ReturnsTempData()
        {
            HomeController controllerUnderTest = new HomeController();
            var result = controllerUnderTest.Details("a1") as ViewResult;
            Assert.AreEqual("foo", result.TempData["Name"]);

        }

Here, we are creating an object of the controller and then calling the action. typecasting the return value as ViewResult and then asserting the result. On running the test, we will find the test is passed and the controller is returning the expected TempData.

Summary

It is always a good practice to write Unit Tests for various Controller’s object. In this post, we learnt to write Unit Tests for:

  1. ViewData of the Controller
  2. TempData of the Controller
  3. ViewBag of the Controller
  4. View of the Controller

I hope you find this post useful, and thanks for reading!