The motivation for this blog entry is to explain the nature and purpose of the tests used in Test-Driven Development. To avoid confusion, I’ll use the expression TDD test to refer to the type of test used in the context of Test-Driven Development. The goal of this blog entry is to clarify the relationship among TDD tests, unit tests, and acceptance tests.
TDD Tests are not Unit Tests
Let’s start with the distinction between TDD tests and unit tests. On the surface, TDD tests are very similar to unit tests. This is not surprising, since you use a unit testing framework such as Visual Studio Tests or NUnit to create both types of tests.
The purpose of a unit test is to test a unit of code in isolation. For example, you might create a unit test that verifies whether a particular class method returns the value that you expect. The standard example of a unit test is a test that verifies the Add() method of a Math class (see Listing 1).
Listing 1 – Math.cs
public class Math
{
public int Add(int val1, int val2)
{
return val1 * val2;
}
}
Listing 2 – MathTests.cs
[TestClass]
public class MathTests
{
[TestMethod]
public void TestAdd()
{
// Arrange
var math = new Math();
// Act
var result = math.Add(2, 3);
// Assert
Assert.AreEqual(5, result);
}
}
The Add() method in Listing 1 is intended to add two numbers together (but was badly written).
The unit test in Listing 2 verifies that 2 + 3 does, in fact, equal 5. If the Add() method is not implemented correctly then the unit tests fails (see Figure 1).
Figure 1 – Failing unit test

In real life, the situation is rarely as simple as this Math example. Typically, a class has many dependencies on other classes. For example, the class in Listing 3 contains validation logic. However, it also calls into a data access class and a logging class. In these cases, you must resort to faking or stubbing the dependent classes.
Listing 3 – Validation.cs
public class Validation
{
private ForumsRepository _repository = new ForumsRepository();
private Logger _logger = new Logger();
public void CreateForumPost(ForumPost post)
{
// Validate forum post
if (String.IsNullOrEmpty(post.Subject))
throw new Exception("Subject is required!");
// Store forum post in database
_repository.CreateForumPost(post);
// Log it
_logger.Log("Add new forum message");
}
}
In a well-designed application, each class has a single responsibility (the SRP principle). A validation class contains only validation logic, a data access class contains only data access logic, and so on. When creating unit tests, you test whether a class satisfies its responsibilities. For example, when unit testing a validation class, you don’t test data access logic. A unit test for the validation class should verify whether the validation logic behaves in the way that you expect.
The purpose of a unit test is to give a developer confidence that a particular part of their application behaves in the way that the developer expects. This is very valuable for regression testing. If you modify code that is covered by unit tests, then you can use the tests to immediately determine whether you have broken existing functionality.
So how does a TDD test differ from a unit test? Unlike a unit test, a TDD test is used to drive the design of an application. A TDD test is used to express what application code should do before the application code is actually written.
Test-Driven Development grew out of a reaction to waterfall development. One important goal of Test-Driven Development is what Kent Beck calls incremental design and what Martin Fowler calls evolutionary design. Instead of designing an application all at once and up front, an application is designed incrementally test-by-test.
When practicing Test-Driven Development, you develop an application by performing these steps over and over again:
1. Create a failing test
2. Write just enough code to pass the test
3. Refactor your code to improve its design
This process is called Red/Green/Refactor because a unit testing framework displays a red bar for a failing test and a green bar for a passing test.
When practicing Test-Driven Development, the first step is always to create a failing test. You use the test to express how you want your code to behave. For example, when building a forums application, you might start by writing a test that verifies whether or not you can post a new message to the forum.
When you write a TDD test, you write the test without making any design decisions up front. Fowler writes:
Classicists, however, think that it's important to only think about what happens from the external interface and to leave all consideration of implementation until after you're done writing the test.
http://martinfowler.com/articles/mocksArentStubs.html#DrivingTdd
When writing a unit test, you should only consider what you want your application to do. After you write the test, you make implementation decisions. Finally, after implementing enough code, you consider how you can refactor your application to have a better design.
A TDD test, unlike a unit test, might test more than a single unit of code at a time. Fowler writes:
Unit testing in XP is often unlike classical unit testing, because in XP you're usually not testing each unit in isolation.
Fowler http://www.artima.com/intv/testdriven4.html
As the design of your application evolves, code that was originally contained in one class might end up in multiple classes. Unlike a unit test, A TDD test can test code that spans multiple classes.
TDD Tests are not Acceptance Tests
A customer acceptance test (also known as an integration test or a functional test) is used to verify that an application behaves in the way that a customer expects. An acceptance test is usually created in collaboration with a customer as an way of determining whether the customer requirements have been met.
The audience for an acceptance test is different than the audience for a TDD test. An acceptance test is created for the benefit of the customer. A TDD test, on the other hand, is created for the benefit of a developer.
Unlike a TDD test, an acceptance test is not created with a unit testing framework. Instead, customer acceptance tests are created with an acceptance testing framework such as Selenium, Fit, FitNesse or Watir/WatiN.
These acceptance testing frameworks enable you to test an application end-to-end. For example, using Selenium, you can simulate posting an HTML form to a web server. Then, you can verify that a particular response was returned by the web server (you can pattern match text returned in the response).
One important difference between a TDD test and an acceptance test is that everything is hooked up when you perform an acceptance test. You perform an acceptance test against the actual web server and database server.
TDD tests, on the other hand, need to execute very fast. You should execute your TDD tests each and every time that you make a change to your code. Because an application might include hundreds (or even thousands) of TDD tests, individual TDD tests must be fast.
Kent Beck has something he calls the 10 minute rule. You should be able to execute all of your TDD tests in less than 10 minutes (and still have time to drink a cup of coffee). If you are running your TDD tests against an actual web server or database then you won’t be able to satisfy the 10 minute rule.
What is a TDD Test?
The best way to understand the purpose of a TDD test is to understand the purpose of Test-Driven Development. According to Fowler:
TDD's origins were a desire to get strong automatic regression testing that supported evolutionary design.
http://martinfowler.com/articles/mocksArentStubs.html#DrivingTdd
First, TDD tests – like unit tests -- support regression testing. You use TDD tests to quickly verify whether you have broken existing application functionality whenever you make a change to the application code. This support for regression testing makes incremental design possible by enabling you to continuously refactor your application. You can mercilessly refactor your application to have a better design because you have the safety net of unit tests.
Second, TDD tests – like acceptance tests -- are used to drive the design of your application. TDD tests act as mini-acceptance tests. A TDD test expresses the task that you need to do next and the criterion for success.
There are several good walkthroughs of Test-Driven Development including:
o Bowling Score Example – Included in Robert and Micah Martin’s excellent book Agile Principles, Patterns, and Practices in C# and partially reproduced here http://www.objectmentor.com/resources/articles/xpepisode.htm.
o Currency Conversion Example – Included in Kent Beck’s excellent book Test-Driven Development by Example.
o Bookmark Collection Example – Included in James Newkirk’s blog. This is a series of posts that describe building a Bookmark Collection.
When practicing Test-Driven Development, you start with a list of user stories that describe, in a non-technical way, how an application should behave. These user stories are developed in collaboration with the customer for the application. Each user story should be, at most, a few sentences long.
In Kent Beck’s walkthrough, he keeps a list of tasks that looks very much like a task list. Implementing one task inspires him to add additional tasks to the list. When he creates a test that corresponds to the task, and implements the code necessary to pass the test, he crosses the task off his list.
For example, when building a forums web application, you might start with the following list of user stories:
· A user should be able to create a new forum post. A forum post includes an author, subject, and body.
· A user should be able to view all of the forum posts on the home page. The latest posts should appear higher than earlier posts.
· A user should be able to reply to an existing post.
· A user should be able to select a particular post and see the post and all of the replies.
This list of user stories evolves as you write the application and you get additional feedback from the customer. You use this initial list of user stories as a starting point.
Next, you pick a user story to implement. Your TDD tests should flow out of the user story. For example, imagine that you pick this story to implement:
· A user should be able to create a new forum post. A forum post includes an author, subject, and body.
In that case, you might start with a TDD test that looks like Listing 4. The test in Listing 4 verifies that you can add a new post to the forums application.
Listing 4 – ForumControllerTests.cs
[TestMethod]
public void ForumPostValid()
{
// Arrange
var controller = new ForumController();
var postToCreate = new ForumPost();
// Act
controller.Create(postToCreate);
}
The test verifies that you can invoke the Create() action on the Forum controller with a new forum post. After you write the test, you can implement the application code required to satisfy the test. In this case, you would need to create a ForumController and ForumPost class.
After you create this first test, and write the code to satisfy the test, you will think of other related tests. For example, you might want to verify that posting a forum message without a subject generates a validation error message. The test in Listing 5 verifies that a validation error message is added to model state when you attempt to post a message without a subject.
Listing 5 – ForumControllerTests.cs
[TestMethod]
public void ForumPostSubjectIsRequired()
{
// Arrange
var controller = new ForumController();
var postToCreate = new ForumPost { Subject = string.Empty };
// Act
var result = (ViewResult)controller.Create(postToCreate);
// Assert
var subjectError = result.ViewData.ModelState["Subject"].Errors[0];
Assert.AreEqual("Subject is required!", subjectError.ErrorMessage);
}
The point here is that the TDD tests are flowing directly from the user stories. The TDD tests are acting like mini-acceptance tests. You are using the TDD tests to drive the building of the application.
Conclusion
The goal of this blog entry was to clarify the difference among TDD tests, unit tests, and acceptance tests. A TDD test is similar to both a unit test and an acceptance test, but it is not the same.
Like unit tests, TDD tests can be used for regression testing. You can use TDD tests to immediately determine whether a change in code has broken existing application functionality. However, unlike a unit test, a TDD test does not necessarily test one unit of code in isolation.
Like acceptance tests, TDD tests are used to drive the creation of an application. TDD tests work like mini-acceptance tests. You create a TDD test to express the application functionality that needs to be implemented next. However, unlike an acceptance test, a TDD test is not an end-to-end test. A TDD test does not interact with a live database or web server.