This is Part 1 in a series of posts.
ASP.Net MVC is designed for testability. Separating the Model, View, and Controller, makes it much easier to test your application. But, the standard MVC template doesn’t allow good unit testing right out of the box. You need to do some coding and add some additional assemblies to do good unit testing.
In this series, you will learn about problems with the default template and how to get around them.I’m not going to do TDD here because I feel you get a better understanding of the needed changes if we walk through changing the code to be more testable rather than jumping straight to TDD. Also, I think you get a better understanding of unit testing if you learn this way.
And you need a good understanding of unit testing to do TDD correctly.
To get started, we need an MVC application. I want to keep it simple so that it’s easier to understand what we’re doing. The example solution I am using is called MVCUnitTesting. You can download the Visual Studio solution if you want to follow along. I used the Internet MVC 4 application template. The application has one simple data entry form and CRUD forms for two supporting lookup tables. Note that when I created the application, I did not check “Create a Unit Test project” on the new project dialog. Here’s the Create Customer page from the application. We will write unit tests for the Customer Controller.
Now that we have our application, we need to assemble our unit test tools. Visual Studio ships with it’s own unit test framework and test runner. The problem with it is the test runner is part of Visual Studio and can’t be pulled out to run automated tests. This means if you aren’t using TFS for Continuous Integration, you need a different unit test framework. I prefer NUnit and will use it for this series.
Before installing NUnit, let’s create an empty project for our tests. Right-click on the solution in Solution Explorer and add a new class library project named UnitTests then delete the .cs file that was created. A good practice is to place unit tests into their own project. This is not something you will distribute with your application.
Now, expand the new UnitTests project node, right-click on References and select Manage NuGet Packages. In the search box, select NUnit, then click Install. This will install NUnit into the the UnitTests project. You will not install it into the MVC project.

You will also need to add a reference to the MVCUnitTesting project.
Now it’s time to write our first unit test, but where to start? The beginning is often a good place, so how about the CustomerController.Index method. Here it is:
1: public ActionResult Index()
2: {
3: return View(db.Customers.ToList());
4: }
I can see two things that you may want to test for. The first, is that the return value is of the expected type. In this case, it’s an ActionResult. The other thing I see is that the model is List<Customer>, so we can check that is correct. So, let’s start with the first thing and make sure we actually get back an ActionResult.
To add the unit test, right-click the UnitTests project and add a new class named CustomerUnitTests. First, add a [TestFixture] attribute to the class. If prompted to add a using statement, do so. Next, create the first method. Unit test methods are public void. By convention, the name of the method tells you what you are testing, so name the method Customer_Index_Returns_ActionResult. You will also need to add a [Test] attribute to the method. As you add the code, Visual Studio may indicate you are missing some references or using statements. Add the ones you’re missing. Here’s the first attempt at writing this test.
1: using System;
2: using System.Collections.Generic;
3: using System.Linq;
4: using System.Text;
5: using System.Threading.Tasks;
6: using System.Web.Mvc;
7: using NUnit.Framework;
8: using MVCUnitTesting.Controllers;
9: using MVCUnitTesting.Models;
10:
11: namespace UnitTests
12: {
13: [TestFixture]
14: public class CustomerUnitTests
15: {
16: [Test]
17: public void Customer_Index_Returns_ActionResult()
18: {
19: // Arrange
20: CustomerController controller = new CustomerController();
21:
22: // Act
23: var actual = controller.Index();
24:
25: // Assert
26: Assert.IsInstanceOf<ActionResult>(actual);
27: }
28: }
29: }
There are several things to note about this code. First, the method has three parts, Arrange, Act, Assert. This is another good practice. In Arrange, you set everything up to run the test. This includes things like getting a reference to the class, creating any values that may need to be passed to the method, etc. Act is where you actually call the method you are tested. Assert is where you validate that the method returned the value you expected.
But there are some issues with the method. For example, you can’t instantiate a new ActionResult. This is because ActionResult is an abstract class and as it turns out, is the parent class for several other data types. Hmmm..looking at the actual return statement of the Index method, we see that it returns a View. That means, View is a subclass of ActionResult. Rather than go through several steps trying to get this to work, I’ll cut to the chase. You need to return a different data type, not something abstract. It needs to be something concrete.
And this is one thing that makes unit testing MVC applications so difficult. Knowing what things are and how to change what gets returned to something you can test for. This takes learning about MVC. And this brings up another good practice, which is, return the most specific data type you can.
In our case, we’re going to return a ViewResult. Here’s the new Index method.
1: public ViewResult Index()
2: {
3: return View(db.Customers.ToList());
4: }
And now the updated test method. Don’t forget to change the name of this method as we will now expect a ViewResult, not an ActionResult.
1: using System;
2: using System.Collections.Generic;
3: using System.Linq;
4: using System.Text;
5: using System.Threading.Tasks;
6: using System.Web.Mvc;
7: using NUnit.Framework;
8: using MVCUnitTesting.Controllers;
9:
10: namespace UnitTests
11: {
12: [TestFixture]
13: public class CustomerUnitTests
14: {
15: [Test]
16: public void Customer_Index_Returns_ViewResult()
17: {
18: // Arrange
19: CustomerController controller = new CustomerController();
20:
21: // Act
22: var actual = controller.Index();
23:
24: // Assert
25: Assert.IsInstanceOf<ViewResult>(actual);
26: }
27: }
28: }
Now that you have the unit test written and you can compile, it’s time to run the test. Unit tests use the terms red and green for fail and pass, so we want our test to be green. There are actually a number of ways to run this test. Let’s start with the NUnit runner.
To get the NUnit runner, go to www.nunit.org and download and install NUnit. Once you’ve done that, launch NUnit.exe. Next you need to setup your test. NUnit does this via NUnit projects. From the NUnit menu, select File –> New Project. I named mine MVCUnitTesting and saved it to the same folder as my MVCUnitTesting Visual Studio solution. This will create a file names MVCUnitTesting.nunit.
Next you need to tell NUnit which assembly to use. Select Project –> Add Assembly and select UnitTests.dll from the bin folder. When that’s done, click Run. If all goes well, you’ll get a green bar.

NUnit also ships with a console application runner for use with Continuous Integration servers.
Running unit tests this way is easy and inexpensive, but you have to step outside Visual Studio. There is documentation on the NUnit site on how to call NUnit from inside Visual Studio, but truthfully, it’s an older, outdated method.
This next method only works with Visual Studio 2012 (and even then, not with the Express edition). Beginning with VS2012, Microsoft opened up the built-in test runner to provide support for third-party test tools. First you have to download NUnit Test Adapter. To do this, select Tools –> Extensions and Updates from the Visual Studio menu. Make sure Online is selected on the left-hand side. Enter NUnit Test Adapter into the search dialog then click Download. You will be prompted to install and then you’ll need to restart Visual Studio.
Once Visual Studio restarts, you should see the Test Explorer window. If not, select Test –> Windows –> Test Explorer on the Visual Studio menu. In the Test Explorer window, click Run.

These first two ways to run tests are free. Now let’s look at some pay-for test runners. The first is Resharper available at www.jetbrains.com. This is a great tool and if you don’t have it, I highly recommend that you purchase it as it will totally change the way you write code. Resharper has adidtional keyboard shortcuts, refactorings, autocode insertion, and many other productivity enhancements. It also includes a test runner that works with NUnit.
To run a test from Resharper, first position your cursor on the test you want to run, then select Resharper –> Unit Tests –> Run Unit Tests from the Visual Studio menu.

The other way to have Resharper run tests is to select Resharper –> Unit Tests –> Run All Unit Tests from Solution. This will run all the tests in the solution and the cursor can be positioned anywhere in the solution.
The last way I’m going to show you how to run unit tests is also a paid add-on. But I think this really is by far the best way to run unit tests. It’s a fairly new product called NCrunch. You download it here. Why is NCrunch superior? First, it automatically runs unit tests. No muss, no fuss. It keeps track of your code and tests as you edit them, recompiles in the background, and then runs the tests in the background. You get immediate feedback on which tests are failing and passing right in the Visual Studio editor.
Additionally, NCrunch automatically shows Code Coverage. This means you know which lines of code are covered by a unit test and which aren’t. It does this by adding a red dot in the VS editor for each line that fails, a green dot if it passes, and a black dot if the line is not under test.
Once you’ve downloaded and installed NCrunch, you need to enable it for the project. From the Visual Studio menu, select NCrunch –> Enable NCrunch. You’ll then need to walk through a series of choices. As you get started with unit tests, here’s how I think you should select options.
The first page is Parallel Execution. Select the default and click Next
On the second page, Engine Execution Mode, again select the default and click Next.
The third page is Ignored Tests. Select the option Let my tests run then click Next. Click Finish and you’re done. This will cause the tests to be run automatically.
Once you’re done with the setup, the tests should run automatically and the results show up inside the Visual Studio editor. Here are the screen captures of the Index method and the test.


Notice that some of the lines have a yellow dot with a green border. This is what NCrunch calls a hot spot. It’s defined as a line of code that runs slowly. I’ll come back to these lines in a bit. First, let’s handle the second test I suggested, that the model attached to the view be List<Customer>. Here’s the new test.
1: [Test]
2: public void Customer_Index_View_Contains_ListOfCustomer_Model()
3: {
4: // Arrange
5: CustomerController controller = new CustomerController();
6:
7: // Act
8: var actual = (List<Customer>)controller.Index().Model;
9:
10: // Assert
11: Assert.IsInstanceOf<List<Customer>>(actual);
12: }
One of the great things about NCrunch is the test is run as soon as you write it. You get immediate feedback. I think this not only makes you more productive, but helps you learn unit testing faster.
Looking at the Controller code, you see that the Model is a List<Customer> and every Customer record in the database should be included. How do we know the List contains all the rows in the Customer table? This is difficult to test as that can change in the database.
Remember the yellow dots with green borders? The code is slow because it actually hits the database. This not only means that the tests are slow, but additional tests could return invalid results as the data changes. It also means THIS IS NOT A UNIT TEST! It is an integration test. Unit tests do not hit the database or external components.
And that’s where I’ll go in Part 2 of this series. We’ll begin to refactor the code so we can avoid the database when running unit tests. It will take a few steps to get there, but I’ll take you along slowly.
Index to posts in this series
Part 1: Getting Started
Part 2: Repositories
Part 3: Mocks
Part 4: Dependency Injection
Part 5: Handling the SelectList
Part 6: The [HttpPost] Method
Part 7: Testing Http Status Codes