Introduction
Purpose
The purpose of this article is to explain what TDD is and give an example in terms of the process.
So what does TDD stand for, well according to Wikipedia it is Test Driven Development but having read around the subject looking at blogs from Brad Wilson it should really be Test Driven Design, or as his want Design By Example but this doesn't fit in the acronym. I'll stick with Test Driven Design.
Approach
Instead of writing the controller and repository first instead I will create the test and use Visual Studio 2010 to automatically generate the classes, methods and properties as dictated by the test.
Patterns
So what about patterns? Well in this example I will use the Dependency Injection, Repository, Mock Object Design and MVC patterns.
Ensure you unblock the zip file once you have downloaded it.
For this example I am using .NET 4 so I will need to use the Moq DLL from:
\Moq.4.0.10827.Final\Moq.4.0.10827\NET40
Use the .msi file.
Install with Typical and use the defaults.
Follow the installation guide here:
http://www.nunit.org/index.php?p=installation&r=2.5.10
C:\Program Files (x86)\NUnit 2.5.10\bin\net-2.0\nunit.exe.config
To add NUnit to Visual Studio tools menu in VS 2010
In Visual Studio have the test project highlighted before running NUnit from the Tool menu.
Coding
Ok, let's get our hands dirty.
Firstly I know that I want to use MVC for this project so we kick off with an empty MVC framework.
Create the MVC project
In Visual Studio 2010: New Project...
ASP.NET MVC 3 Web Application
TDDBlog
Empty
View engine: Razor
Create the test project
Create a new Class Library Project called TDDBlog.Tests
Right Click and Add a reference to TDDBlog from the Projects tab
Right click and Add a reference to nunit.framework from the .NET
Create a new folder structure \Library
Copy the Moq.dll to \Library\Moq
Right click and Add a reference to Moq.dll
Delete Class1.cs
Create a test for the controller
So we know that we are dealing with a Blog so I will want a BlogController. But before I go ahead and start building that up I will create the test first.
So in the TDDBlog.Tests
Create a new folder structure \Controllers
Add a new class: BlogControllerTest and make it public, as we are using NUnit we want to tell NUnit that the class we are using is testable, this requires us to reference the NUnit framework in our code and add the TestFixture attribute to the class:
Let's check to see if it builds.
Ok, hopefully you had some joy there. So I want to return a list of blog entries and check the format of the URL.
As we are using MVC the test is a call on the Index Action:
Index returns a list of blog entries with correct Urls
You will notice the [Test] attribute on the method, this as you may have guessed tells NUnit that this is a test.
Hook up with NUnit
Now we have our empty test lets run it in NUnit.
Now we have NUnit set up in the Tools menu we can run it from there. Ensure you highlight the TDDBlog.Tests project.
If it does not load with the correct DLL, simply: File > Open Project and select the TDDBlog.Tests.dll.
Click Run to execute the test.
We will see a green light, this is the default behaviour; if no test content is present then the is nothing to fail.
Start building the test and let the compiler guide you
So our blog will have BlogEntry class objects, to set this up we will Mock a list of these.
A Mock defines the results from calls it does not set the content on objects. I like Moq as it uses Lambda expressions.
Create a Mock for BlogEntry:
Add a reference to Moq in your code:
Build the project, it will fail with:
So no surprise, we need to create this class.
Left click on BlogEntry in the test method. If you have reSharper installed you will get a red light bulb appear on the left allowing you to create a new class called BlogEntry Visual Studio 2010 has the same functionality. Hover over BlogEntry and a icon with a tool tip of, 'Options to help bind the selected item' appears; extend this and click on 'Generate new type...'.
This will allow you to specify the location and access:It will also add the reference to the file.
Next we want to set some fields on the new class again this do this from the test.
So we know that this won't compile and from what we have learnt we can get our test to do some work for us. Click on Id, hover and 'Generate property stub for 'ID' in 'TDDBlog.Models.BlogEntry'.
So your BlogEntry class should look like:
Modify the class to use the correct types and add virtual (this is required for Moq):
Create a couple of other BlogEntries.
SetupGet is used for Properties on a Class.
The next thing to do is to work out how we are going to store this, notice I say how not where. Let's say we are going to use a repository pattern. Mock an IBlogsRepository (again don't create it first).
Follow the same process as before:
You will need to add a reference to Systems.Collections.Generic.
Setup works in the same way as SetupGet but is for method calls not Properties on a Class.
Add the interface method for GetAllBlogEntries by clicking on the method and generating from the test: 'Generate method stub for 'GetAllBlogEntries' for 'TDDBlog.Models.IBlogsRepository'
The interface will look like:
Add the correct return type:
So that is our repository set up and Mocked, and the objects inside it Mocked.
Test the Controller
We will inject the controller with the repository.
In the test we will initialise the controller - we will start with the test code before getting the test code to create the Controller:
You know the steps by now:
Again click and hover on the BlogController, and 'Generate constructor stub in 'TDDBlog.Controllers.BlogController'.
This generates:
Inherit the BlogController from Controller and add a reference to System.Web.Mvc.
Next we need to call the controller method to get the result. We are going to assume that the Index call is going to be used:
We need to ensure out test project knows what a ViewResult is, add System.Web.Mvc to the TDDBlog.Tests project.
Then get Visual Studio 2010 add the reference to the file by hover etc...
Create the Index method in the Controller by the usual method as described above.
Start testing
We want to get the URL for each blog entry but this will not be in the repository.
The Url property does not exist at this point in the BlogEntry, so add the property stub from the test, set the correct type:
Notice this is not set to virtual as it is not going to be Mocked or used by the repository.
Right, that is the test code complete, so what happens when we run our test?
Expected failure
So we are seeing red! Let's look at the output window:
TDDBlog.Tests.Controllers.BlogControllerTest.IndexReturnsAListOfBlogEntriesWithCorrectUrls:
Not a big shock as we have not implemented the Index method on the controller yet.
Let's do this now:
Ok, that makes sense, we have not changed the controller to set the Url, this is a good test as before we were just returning what we put in the Mock framework.
So we need to change the controller:
The test now passes; woo and indeed hoo!
Summary
So, we created an MVC project designed by our tests. We only implemented what was required so there was no redundant code which is something that can happen when just cracking out the code.
As I used Moq, I did not have to configure or populate a database or some other repository.
By using Dependency Injection the code would be easily extendable to inject a repository to the Controller using a dependency injector like Ninject.
One gotcha that you may have come across is that if the BlogEntry Url property is set to virtual then the value will not be set in the controller.
I have uploaded the source code for TDD with ASP.NET MVC 3, Moq and Dependency Injection on githib, take a look and fork it.
Purpose
The purpose of this article is to explain what TDD is and give an example in terms of the process.
So what does TDD stand for, well according to Wikipedia it is Test Driven Development but having read around the subject looking at blogs from Brad Wilson it should really be Test Driven Design, or as his want Design By Example but this doesn't fit in the acronym. I'll stick with Test Driven Design.
Approach
Instead of writing the controller and repository first instead I will create the test and use Visual Studio 2010 to automatically generate the classes, methods and properties as dictated by the test.
Patterns
So what about patterns? Well in this example I will use the Dependency Injection, Repository, Mock Object Design and MVC patterns.
Project
A simple repository call that returns a list of blog entries with URLs built from the title field.
Toolset
To use Moq for the Mock Object Framework
Version: 4.0.10827
Mock objects are faked objects that imitate the activities of real objects in a controlled manner.
To mock an interface to the data access component while testing the business logic. This avoids writing code until you are ready to do so.
Moq takes advantage of recent VB.NET and C# language features such as lambdas and generics. When creating mock objects with Moq, you use lambda expressions to represent the methods and properties that you want to mock.
Download instructions
Download Moq from: http://code.google.com/p/moq/downloads/listEnsure you unblock the zip file once you have downloaded it.
For this example I am using .NET 4 so I will need to use the Moq DLL from:
\Moq.4.0.10827.Final\Moq.4.0.10827\NET40
NUnit
Version: 2.5.10.11092
NUnit is a unit testing framework for .NET. The units of code are tested to ascertain if they are fit for use.
Download instructions
Download NUnit from here: http://www.nunit.org/index.php?p=downloadUse the .msi file.
Install with Typical and use the defaults.
Follow the installation guide here:
http://www.nunit.org/index.php?p=installation&r=2.5.10
C:\Program Files (x86)\NUnit 2.5.10\bin\net-2.0\nunit.exe.config
To add NUnit to Visual Studio tools menu in VS 2010
In Visual Studio have the test project highlighted before running NUnit from the Tool menu.
MVC for the Web Application Framework
Version: ASP.NET MVC 3.
The Model View Controller is a software architecture software pattern.
Coding
Ok, let's get our hands dirty.
Firstly I know that I want to use MVC for this project so we kick off with an empty MVC framework.
Create the MVC project
In Visual Studio 2010: New Project...
ASP.NET MVC 3 Web Application
TDDBlog
Empty
View engine: Razor
Create a new Class Library Project called TDDBlog.Tests
Right Click and Add a reference to TDDBlog from the Projects tab
Right click and Add a reference to nunit.framework from the .NET
Create a new folder structure \Library
Copy the Moq.dll to \Library\Moq
Right click and Add a reference to Moq.dll
Delete Class1.cs
Create a test for the controller
So we know that we are dealing with a Blog so I will want a BlogController. But before I go ahead and start building that up I will create the test first.
So in the TDDBlog.Tests
Create a new folder structure \Controllers
Add a new class: BlogControllerTest and make it public, as we are using NUnit we want to tell NUnit that the class we are using is testable, this requires us to reference the NUnit framework in our code and add the TestFixture attribute to the class:
using NUnit.Framework;
namespace TDDBlog.Tests.Controllers
{
[TestFixture]
public class BlogControllerTest
{
}
}
Let's check to see if it builds.
Ok, hopefully you had some joy there. So I want to return a list of blog entries and check the format of the URL.
As we are using MVC the test is a call on the Index Action:
Index returns a list of blog entries with correct Urls
[Test]
public void IndexReturnsAListOfBlogEntriesWithCorrectUrls()
{
}
Now we have our empty test lets run it in NUnit.
Now we have NUnit set up in the Tools menu we can run it from there. Ensure you highlight the TDDBlog.Tests project.
If it does not load with the correct DLL, simply: File > Open Project and select the TDDBlog.Tests.dll.
Click Run to execute the test.
We will see a green light, this is the default behaviour; if no test content is present then the is nothing to fail.
Start building the test and let the compiler guide you
So our blog will have BlogEntry class objects, to set this up we will Mock a list of these.
A Mock defines the results from calls it does not set the content on objects. I like Moq as it uses Lambda expressions.
Create a Mock for BlogEntry:
var mockBlogEntry1 = new Mock<BlogEntry> ();
using Moq;
The type or namespace name 'BlogEntry' could not be found (are you missing a using directive or an assembly reference?)
So no surprise, we need to create this class.
Left click on BlogEntry in the test method. If you have reSharper installed you will get a red light bulb appear on the left allowing you to create a new class called BlogEntry Visual Studio 2010 has the same functionality. Hover over BlogEntry and a icon with a tool tip of, 'Options to help bind the selected item' appears; extend this and click on 'Generate new type...'.
This will allow you to specify the location and access:
- Access: public
- Kind: class
- Location: TDDBlog
- Create new file: Models\BlogEntry.cs
Next we want to set some fields on the new class again this do this from the test.
const int id1 = 1;
const string title1 = "My first blog Entry";
const string content1 = "I love blogging, it is so cool";
mockBlogEntry1.SetupGet(x => x.Id).Returns(id1);
mockBlogEntry1.SetupGet(x => x.Title).Returns(title1);
mockBlogEntry1.SetupGet(x => x.Content).Returns(content1);
So your BlogEntry class should look like:
namespace TDDBlog.Models
{
public class BlogEntry
{
public Id Id { get; set; }
public Title Title { get; set; }
public Content Content { get; set; }
}
}
namespace TDDBlog.Models
{
public class BlogEntry
{
public virtual int Id { get; set; }
public virtual string Title { get; set; }
public virtual string Content { get; set; }
}
}
const int id2 = 2;
const string title2 = "I'm still in to this";
const string content2 = "I'm still enjoying my blogging";
var mockBlogEntry2 = new Mock<BlogEntry>();
mockBlogEntry2.SetupGet(x => x.Id).Returns(id2);
mockBlogEntry2.SetupGet(x => x.Title).Returns(title2);
mockBlogEntry2.SetupGet(x => x.Content).Returns(content2);
const int id3 = 3;
const string title3 = "OK!";
const string content3 = "Ok, I'm done!";
var mockBlogEntry3 = new Mock<BlogEntry>();
mockBlogEntry3.SetupGet(x => x.Id).Returns(id3);
mockBlogEntry3.SetupGet(x => x.Title).Returns(title3);
mockBlogEntry3.SetupGet(x => x.Content).Returns(content3);
The next thing to do is to work out how we are going to store this, notice I say how not where. Let's say we are going to use a repository pattern. Mock an IBlogsRepository (again don't create it first).
var blogRepository = new Mock<IBlogsRepository>();
Follow the same process as before:
- Access: public
- Kind: interface
- Project: TDDBlog
- Create new file: Models\IBlogsRepository
blogRepository
.Setup(p => p.GetAllBlogEntries())
.Returns(new List<BlogEntry> { new BlogEntry.Object });
Setup works in the same way as SetupGet but is for method calls not Properties on a Class.
Add the interface method for GetAllBlogEntries by clicking on the method and generating from the test: 'Generate method stub for 'GetAllBlogEntries' for 'TDDBlog.Models.IBlogsRepository'
The interface will look like:
namespace TDDBlog.Models
{
public interface IBlogsRepository
{
object GetAllBlogEntries();
}
}
namespace TDDBlog.Models
{
public interface IBlogsRepository
{
IEnumerable<BlogEntry> GetAllBlogEntries();
}
}
Test the Controller
We will inject the controller with the repository.
In the test we will initialise the controller - we will start with the test code before getting the test code to create the Controller:
BlogController blogController = new BlogController((IBlogsRepository)blogRepository.Object);
- Access: public
- Kind: class
- Project: TDDBlog
- Create new file: Controllers\BlogController.cs
Again click and hover on the BlogController, and 'Generate constructor stub in 'TDDBlog.Controllers.BlogController'.
This generates:
namespace TDDBlog.Controllers
{
public class BlogController
{
private Models.IBlogsRepository iBlogsRepository;
public BlogController(Models.IBlogsRepository iBlogsRepository)
{
// TODO: Complete member initialization
this.iBlogsRepository = iBlogsRepository;
}
}
}
Inherit the BlogController from Controller and add a reference to System.Web.Mvc.
Next we need to call the controller method to get the result. We are going to assume that the Index call is going to be used:
ViewResult viewResult = blogController.Index() as ViewResult;
Then get Visual Studio 2010 add the reference to the file by hover etc...
Create the Index method in the Controller by the usual method as described above.
public ViewResult Index()
{
throw new NotImplementedException();
}
Start testing
We want to get the URL for each blog entry but this will not be in the repository.
List<BlogEntry> blogEntries = (System.Collections.Generic.List)viewResult.ViewData.Model;
BlogEntry blogEntry1 = blogEntries[0];
Assert.AreEqual(id1, blogEntry1.Id);
Assert.AreEqual(title1, blogEntry1.Title);
const string url1 = "my-first-blog-entry";
Assert.AreEqual(url1, blogEntry1.Url);
Assert.AreEqual(content1, blogEntry1.Content);
BlogEntry blogEntry2 = blogEntries[1];
Assert.AreEqual(id2, blogEntry2.Id);
Assert.AreEqual(title2, blogEntry2.Title);
const string url2 = "I'm still in to this";
Assert.AreEqual(url2, blogEntry2.Url);
Assert.AreEqual(content2, blogEntry2.Content);
BlogEntry blogEntry3 = blogEntries[2];
Assert.AreEqual(id3, blogEntry3.Id);
Assert.AreEqual(title3, blogEntry3.Title);
const string url3 = "ok";
Assert.AreEqual(url3, blogEntry3.Url);
Assert.AreEqual(content3, blogEntry3.Content);
public string Url { get; set; }
Right, that is the test code complete, so what happens when we run our test?
Expected failure
So we are seeing red! Let's look at the output window:
TDDBlog.Tests.Controllers.BlogControllerTest.IndexReturnsAListOfBlogEntriesWithCorrectUrls:
TDDBlog.Tests.Controllers.BlogControllerTest.IndexReturnsAListOfBlogEntriesWithCorrectUrls:
System.NotImplementedException : The method or operation is not implemented.Not a big shock as we have not implemented the Index method on the controller yet.
Let's do this now:
public ViewResult Index()
{
return View(iBlogsRepository.GetAllBlogEntries());
}
Ok, run again. Hmm red again what now:
TDDBlog.Tests.Controllers.BlogControllerTest.IndexReturnsAListOfBlogEntriesWithCorrectUrls:
Expected: "my-first-blog-entry"
But was: null
So we need to change the controller:
public ViewResult Index()
{
IEnumerable<BlogEntry> blogEntries = iBlogsRepository.GetAllBlogEntries();
foreach (BlogEntry blogEntry in blogEntries)
{
blogEntry.Url = blogEntry.Title.
Replace("'", string.Empty).
Replace("!", string.Empty).
Replace(" ", "-").
ToLower();
}
return View(blogEntries);
}
Summary
So, we created an MVC project designed by our tests. We only implemented what was required so there was no redundant code which is something that can happen when just cracking out the code.
As I used Moq, I did not have to configure or populate a database or some other repository.
By using Dependency Injection the code would be easily extendable to inject a repository to the Controller using a dependency injector like Ninject.
One gotcha that you may have come across is that if the BlogEntry Url property is set to virtual then the value will not be set in the controller.
I have uploaded the source code for TDD with ASP.NET MVC 3, Moq and Dependency Injection on githib, take a look and fork it.