Introduction
In this article, we have a look at Test Driven Development with an example. The example is Factorial calculator application. This simple application shows us how to develop an application by test driven development. I will write the "Test Driven Development" as "TDD" in article.
Background
When I first faced the Test Driven Development, I thought "it is unnecessary". But later, I read the articles about it and I show that TDD prevents the errors and problems before the delivered projects. It also creates reliable products, shows code coverages. These benefits were enough for me to begin TDD.
In this article, we will use the Visual Studio default Unit Test Framework. But if you don't want to use default framework, you have more choices in the market of Unit Tests.
Before You Start
Before writing your code, you should determine the requirements of the application. We will be developing a Factorial application in this article. So we should determine the Factorial requirements. Later, we can determine the test methods. If you want, you can directly begin writing tests and skip these steps. But making is worth it.
Requirements
- Factorial calculates the multiplication of the all positive numbers less than or equal Target Number(n).
- Target Number(n) is a non-negative integer.
Unit Tests
- Zero factorial is One 0! = 1
- One factorial is One 1! = 1*0! = 1
- Two factorial is Two 2! = 2*1! = 2
- Three factorial is Six 3! = 3*2! = 6
First step is creating a solution named FactorialApplication
. And add a test project named FactorialCalculatorTests
and a class library named FactorialCalculator
in solution.
And now create a new class and write the first test method.
Test 1: Zero Factorial is One
[TestMethod]
public void ZeroFactorialIsOne()
{
Factorial calculator = new Factorial();
}
As you can see above, I created a calculator
object that is of type Factorial
but there is no class named Factorial
. And you will get a lot of red squiggly lines under Factorial
word.
Let's create a class using options menu under the Factorial
Word.
[TestMethod]
public void ZeroFactorialIsOne()
{
Factorial calculator = new Factorial();
float result = calculator.GetFactorialOf(0);
Assert.AreEqual(1, result);
}
Yes, now I added a new result
variable and assigned a calculator.GetFactorialOf(0)
method result in it. But there is no method of Factorial
in such. And I created a method in Factorial
class.
Now we can have a look at the Factorial
class.
public class Factorial
{
public float GetFactorialOf(int p)
{
throw new NotImplementedException();
}
}
And now let's run the test method and see the result.
The test failed because we created method GetFactorialOf(int p)
but did not implement it as seen above. Now we should do minimum intervention to pass the test.
public class Factorial
{
public float GetFactorialOf(int p)
{
return 1;
}
}
The test method can pass now. Because assertion has verified.
Test 2: One Factorial is One
And now, we can create our second method. New assertion is "One Factorial is One". The new test method is as follows:
[TestMethod]
public void OneFactorialIsOne()
{
Factorial calculator = new Factorial();
float result = calculator.GetFactorialOf(1);
Assert.AreEqual(1, result);
}
This method has passed as well because GetFactorialOf(int p)
method still supports our assertion.
Test 3: Two Factorial is Two
The third assertion is "Two factorial is Two".
[TestMethod]
public void TwoFactorialIsTwo()
{
Factorial calculator = new Factorial();
float result = calculator.GetFactorialOf(2);
Assert.AreEqual(2, result);
}
This method failed as follows:
Assert exception is shown, expected value is Two but method returned One. Now we should make minimum modification on GetFactorialOf(int p)
method to pass the method. The modification shouldn't affect the other test results.
public class Factorial
{
public float GetFactorialOf(int p)
{
if (p < 2)
return 1;
return p;
}
}
Test 4: Three Factorial is Six
[TestMethod]
public void ThreeFactorialIsSix()
{
Factorial calculator = new Factorial();
float result = calculator.GetFactorialOf(3);
Assert.AreEqual(6, result);
}
But now this assertion failed.
New modification is required on GetFactorialOf(int p)
method.
public float GetFactorialOf(int p)
{
if (p < 2)
return 1;
return p * GetFactorialOf(p-1);
}
And the solution is as follows. Now we can use this FactorialCalculator
library anywhere we want. I used in a class library named Calculator
.
class Program
{
static void Main(string[] args)
{
Factorial calculator = new Factorial();
for (int i = 0; i < 14; i++)
{
Console.WriteLine(calculator.GetFactorialOf(i));
}
}
}
Points of Interest
The most impressive aspect of TDD for me is that initially, there is no code and while test methods developing the required codes are created automatically. There is no need for planning the classes, no need to plan the variables and so on. Unnecessary operations are not implemented. We implement only requirements specification as needed. Everything is determined during the test period.
The other point is any test should not affect any other. And method implementations should not affect test results. For example, if one method is working correctly for one test, but working wrong other methods, then this is an undesired result.
Any changes of product methods require the running the tests. We did this during the application.
History
This article shows us how to create unit tests and steps of the unit testing simply. And we developed an Factorial application. After the test methods, the mainclass generated and it is ready to use. If you can see the shortcomings of the application, you can modify the methods. But any change of application requires the running tests to be on.