Traditionally TDD has gone hand in hand with the flexibility offered by the testing framework as well as the platform’s testability support. The ASP.NET MVC framework was built with testability in mind and it has only improved with release of MVC 4. This also means, as a TDD practitioner, you find it much easier to write Unit Tests against an ASP.NET MVC app.
In this article, I would like to cover some of the key steps involving how to develop an ASP.NET MVC application using TDD (Test Driven Development). I will use xUnit.NET (1.9v) as the Unit Testing framework and the Moq (4.0v) as the mocking/isolating framework.
If you are interested in Unit Testing, check out Visual Studio 12 Unit Testing – What’s New and ASP.NET MVC Unit Tests with UnityAutoMoq Container
Before I get into the TDD code samples, I would like to give you an overview of both xUnit.NET and VS 2012 from TDD point of view. In the second half of the article, I will focus on building a simple ASP.NET MVC application using TDD and xUnit.NET.
This article is published from the DNC Magazine – A Free High Quality Digital Magazine for .NET professionals published once every two months.
This month's edition features hot topics like ASP.NET MVC4, SignalR, Knockout.js, jsRender, TDD, Visual Studio ALM, HTML5, SharePoint, Windows Azure and Metro Applications amongst others. Not to mention, a freewheeling interview with Ayende Rahien, the man behind RavenDB.
Download this Free Magazine Here
xUnit.NET and TDD
Brad Wilson, one of the co-authors of xUnit.NET framework comments on his blog - “We wanted xUnit.net to be a framework that was first and foremost for TDD (erm, DbE) practitioners.”
As per Brad’s comment, the xUnit.NET framework has been designed and developer to support TDD. This is great because xUnit.NET allows developers to move away from the QA/Test type mind set, and to purely concentrate on the design of the application. This is why xUnit.NET has attributes such as [Fact], and [Theory] etc. xUnit.NET also provides much cleaner test API, which makes lot easier to focus on TDD itself. For example xUnit.NET does not provide attributes such as [TestClass], [TestInitialize] or [TestCleanup], which you might have come across in frameworks such as MSTest. Instead xUnit.NET uses the test class constructor, and Dipose() method (In IDisposable) etc.
xUnit.NET and TDD Tooling support
Most TDD Developers who use xUnit.NET also use plugins such as TestDriven.NET and ReShaper etc. These tools in conjunction with Visual Studio make TDD experience much better. Visual Studio 2012 (VS2012) also has a strong emphasis on TDD.
VS 2012 has a new Unit Test Explorer, which makes your Unit Testing/TDD experience much more interesting than before. The Unit Test explorer has no knowledge of any of the Unit Testing frameworks. In order to make your Unit Test runnable within VS, you just simply have to install your favorite test adapter. For the MVC-TDD demonstrations, I will use the xUnit.NET test adapter.
One of the key points that contribute to the productivity of a TDD Developer is the ability to seamlessly switch between the production code, Unit Tests and the Test Result. The new Unit Test Explorer has been designed to make you feel more connected between your production code, Unit Tests and the Test Result.
To use xUnit you need to install the xUnit Test Runner from the Visual Studio 2012 Extensions Manager. Once installed, you should be able to see your xUnit.NET Unit Tests within Unit Test Explorer.
ASP.NET MVC-TDD Application
What we going to build here is a very simple ASP.NET MVC app using TDD and xUnit.NET. The application manages list of cars in a car dealership.
For this demo, I’m going to use the new VS 2012 RC (VS 2012 has RTM’ed). First we create a new ASP.NET MVC 4 project. Note that when you first create a new ASP.NET MVC project, you get the option to select your preferred Unit Testing framework. Since there is no xUnit.NET project template for VS 2012 available yet, I’m going to skip this step and add a standard C# class library for the Unit Tests project. I will also reference xunit.dll within the Unit Test project.
Let’s say we have a requirement to display list of cars. Note that this is a simple example, but the TDD concepts you apply here remain same for larger applications.
I’m going to add few files to the Solution Explorer as below. Note that we do not have any behavior being implementation in these files yet.
Within ASP.NET MVC project:
Unit Test project:
The first step of the TDD is to write the Unit Test. The first behavior that I would like to verify is:
The Action method “List” should return the View name “List”
Let’s go ahead and write the Unit Test to verify this behavior.
Note: This code assumes that you have the xUnit namespace and the System.Web.Mvc namespace imported accordingly.
The [Fact] attribute identifies the Unit Test in xUnit.NET.
I divided my Unit Test method name into 3 sections separated by underscore ‘_’ - the subject, scenario/condition, and the result. This explains the exact intention of my Unit Test. Note that the List Action within the CarDealershipController does not have the implementation yet.
The next important step is to run the Unit Test. Some people think this is a waste of time since we don’t have the implementation and it is obvious that the test is going to fail. It is important to start with a failing test because, we need to be sure that it was failing before, so we can write enough production code pass the test.
Let’s run this Unit Test and you can see the Test fails. This reflects the “RED” part of the RED, GREEN, and YELLOW in Test Driven Development.
Now let’s implement the minimum code that required making our Unit Test pass.
Note that I haven’t implemented the View “List”. We are only concerned about the behavior of the server side code, therefore we do not need to include a View at this stage of the development. Let’s re-run the Unit Test. As you see, this time the Unit Test passes.
This is the “GREEN” part of TDD. Now we are confident when the “List” Action executes and it returns the ViewName “List”.
Refactoring for additional requirements
We haven’t finished with the Car Dealership requirement yet. The next step is to retrieve list of cars to the Controller’s Action. Then this list can be used by the View. The behavior that we want to verify is -
When the Action Executes, the associated Model contains a list of cars
Our Unit Test is as shown here:
Let’s run this Unit Test. As we would expect, the Test fails. The exception suggests that there is no model associated (i.e. null ref exception) with the returned result.
As a TDD developer, I find myself getting into a code-test-code-test loop. As soon as I write a bit of production code, I want to make sure that I did not break any of my existing Unit Tests. Doing this task repetitively, especially with a large code base can be quite annoying. However VS 2012 can be configured to run Unit Test automatically after every successful build/compilation. To enable this, select “TEST” from the menu, and select Test Settings, and then “Run Tests After Build”.
Our next step is to make the failing test pass. In order to do this we need refactor the Controller’s Action. In TDD life cycle, this falls in to “YELLOW” which is the Refactor.
First I‘ll add some code to the interface ICarDealershipRepository. So we can consume the method GetCarList() within the CarDealershipController. At this stage, I do not require the implementation of this interface. Our aim is to just add enough code to pass the failing Unit Test.
Now we change the Controller’s constructor to accept the ICarDealershipRepository interface and call the method GetCarList() as shown here.
Notice that due to the new parameterized constructor, we are unable to compile our existing Unit Test. Our next step is to fix those tests. At the same time, we can refactor the existing Unit Tests for greater maintainability.
I’m going to introduce a constructor to the Unit Test class. xUnit.NET constructor can execute code that requires executing before each and every test. This is equivalent to [TestInitialize] attribute in MSTest. Some of the repeated code in each Unit Test can also be placed within the constructor.
At the beginning of the article, I mentioned about the Moq isolation framework. Using Moq, I’m going to configure/setup the CarDealershipRepository’s GetCarList method to return fake data.
Moq setup method on the repository is configured to return fake data to the Action List.
Now when we run both the tests, they pass.
It is important to run all Unit Tests (at least in the same area) after every refactor. This is because we want to make sure the refactoring did not cause existing Unit Tests to fail. If any of the existing Unit Tests fails, we would refactor the production code with the smallest possible change to make the failing Test pass.
So far, what we saw is a pattern where we add a Unit Test, write enough production code to pass that Unit Test, add a new Unit Test, refactor the code to pass the new Unit Test, and re-run all Unit Tests. If we can put this into a diagram, it looks like this.
TDD with xUnit.NET Data Theories
In this example, we will look at xUnit.NET Data Theories and Unit Testing an Action Filter using TDD. Let’s assume we have a new requirement where we want to log certain messages depending on a flag returned by query string parameters. For instance, if the flag has a value “true”, “1”, or “yes”, then we simply log a message. Sample query strings parameters would look like this.
To fulfill this requirement, I’m going to introduce a couple of classes.
LogFilterAttribute (An ActionFilterAttribute ) - LogFilterAttribute overrides the OnActionExecutingMethod. There is no implementation for this method yet.
ILoggerInterface has the Log method, which accepts the message to be logged.
Note that we do not require the real implementation of this interface at this stage.
Unit Testing Action Filter:
Similar to our previous TDD sample, we first write the Unit Test. The skeleton of the Unit Test looks like this.
This Unit Test is to verify, for a given set of query string parameters, whether the ILoggerService.Log(message) method being called only once.
Notice that we also have a new attribute called [Theory]. If you have read Brad Wilson’s, 'It is not TDD, its Design By Example', he explains the difference between [Theory] and [Fact] attributes.
The above Unit Test is parameterized. The parameter ‘queryStringValue’, is passed into the Unit Test and contains the value provided by the InlineData attribute. Since we have three InlineData attributes, the test runner executes the Unit Test 3 times for each query string parameter.
Let’s add some code to the Unit Test to satisfy the above expectation.
As you see in the above Unit Test, I do not have the “stubFilterContext” and the “logServiceMock” being declared yet. In order to stub the filterContext, which is the ActionExecutingContext, we need stub few other instances.
We also need a stub HttpContext, and a stub RequestContext so we can configure the stubbed instances to return fake query strings. Finally we need to initialise the Mock, so we can perform the verification on the Log(message) method.
Here is the completed Unit Test.
We are still unable to compile and run this Unit Test as there is no ILoggerService property within SUT. Let’s create the property in the SUT so we can run the Unit Test. The Test Results are shown below.
As you would expect the Unit Tests fail due to three InlineData attributes.
Our next task is to just add enough production code to make these tests pass.
Let’s run those failing Unit Tests.
All Unit Tests are now passing including the ones I wrote before. The TDD life cycle continues as I continue to add new tests to design the behavior of this method. For example, I can add new Unit Test to verify the design of the code that handles invalid query string arguments. Then write a Unit Test, make the test fail, and make the smallest change/refactor to make the Test pass. Finally re-run all Unit tests and ensure they all pass.
In this article, we looked at some of the key concepts behind building an ASP.NET MVC application, using TDD and xUnit.NET. We also learned some of the TDD friendly features that xUnit.Net offers. We looked at some of the enhancements that VS 2012 provides in order to make TDD experience seamless.
We explored how to Unit Test an Action method using TDD and xUnit.NET. We also looked at xUnit.NET DataTheory/InlineData attribute, and used TDD to Unit Test an ActionFilter.
The entire source code of this article can be downloaded on GitHub over here (click on zip to download as a .zip)