Chapter 3: Getting Started
In this chapter you will see step by step how to create and run a simple test
project using Gallio and its default test framework, MbUnit v3. It's assumed
that you already know how to create projects and add references in Visual
Studio, but no prior knowledge of unit testing or test frameworks is assumed.
The screenshots were taken in Visual Studio 2008, but the steps are the same for
Visual Studio 2005 as well.
Let's start by creating a new class library project in Visual Studio called SimpleLibrary. Delete the default class (normally
Class1) that it's added by Visual Studio and add a new one called
Fibonacci. It will be a pretty simple public class
with only one method called Calculate, as shown
here:
C#
namespace SimpleLibrary
{
public
class Fibonacci
{
public static int
Calculate(int x)
{
return Calculate(x - 1) + Calculate(x - 2);
}
}
}
VB
Public Class
Fibonacci
Public
Shared Function Calculate(ByVal
x As Integer)
As Integer
Return Calculate(x - 1) + Calculate(x
- 2)
End
Function
End Class
We will write some tests to verify that this method is working properly. In a
test-driven methodology we would have done it the other way around, that is, we
would have created a test, made it fail and then we would have implemented the
Calculate method to make it pass, just to start over in what is known as the
"red, green, refactor" cycle. Since the chosen the methodology doesn't have an
effect on the way we write tests, we won't do things in a TDD way.
Tests should never be put in your production code,
but in separate projects/assemblies. Add a new class library project to the
SimpleLibrary solution called SimpleLibrary.Test,
delete the default class and add a new one called
FibonacciTest. It's a common practice to name a test project after the
project is testing plus .Tests, and to name a unit test class after the
class it's testing plus .Test.
Now, still in the test project, you need to add a reference to the SimpleLibrary
project, and also to the Gallio.dll and MbUnit.dll assemblies that you can find
in the [Gallio install folder]\bin folder. Note that the common practice is to
have this assembly as well as other referenced assemblies in a custom folder in
your solution, mainly for location independency and versioning issues, but we
will cover this scenario in other chapters.
At this point, your solution should look like this:
With the project structure and references set up we can now write the first unit
test. The code is the following:
C#
using System;
using SimpleLibrary;
using MbUnit.Framework;
namespace SimpleLibrary.Test
{
[TestFixture]
public
class FibonacciTest
{
[Test]
public void FibonacciOfNumberGreaterThanOne()
{
Assert.AreEqual(Fibonacci.Calculate(6),
8);
}
}
}
VB
Imports SimpleLibrary
Imports MbUnit.Framework
<TestFixture()> _
Public Class
FibonacciTest
<Test()> _
Public
Sub FibonacciOfNumberGreaterThanOne()
Assert.AreEqual(Fibonacci.Calculate(6), 8)
End
Sub
End Class
Notice the things we did in the previous code:
- We imported the SimpleLibrary namespace
- We imported the MbUnit.Framework namespace
- We decorated the FibonacciTest class with the TestFixture
(which is defined in the MbUnit.Framework namespace)
- We made the FibonacciTest class public
- We added a new public method called
FibonacciOfNumberGreaterThanOne, which doesn't return a value.
- We decorated the FibonacciOfNumberGreaterThanOne method with the
[Test] attribute
- We added a call to the Assert.Equal method
You may be wondering what's the call to the Assert.AreEqual method supposed to
do. Not too much in fact: it only checks that the return value of the call to
Fibonacci.Calculate(6) is equal to 8. The Assert class is very important because
it contains a lot of helpful methods that make writing tests easier.
Now we have our first unit test, but how do we execute it? Gallio comes bundled
with 7 different runners, that is, programs or plugins for other programs that
allows you to execute tests. This time we will use Icarus,
the graphical runner, because it's a standalone application (meaning that you
don't need to install anything else to run it). The Gallio installer creates a
shortcut for it in the programs folder of the start menu, so it's pretty easy to
launch it:
Once Icarus is running, go to the Assemblies->Add
Assemblies...
menu:
Browse to the folder where you put the solution and look for the
SimpleLibrary.Test.dll assembly (probably located in bin\Debug under the test
project's folder). The test tree is populated as shown in this screenshot:
You can see the MbUnit version under the Root node, and under it the names of
the assembly, the fixture and the test method. The next step is to execute the
test, for which you only need to press the Start
button. After doing so we see that it passes:
But what does it mean for a test to "pass"? It means that it was executed, all
its assertions were true and no exception was thrown. This is the basic
structure of a test in the so called state-based testing: create one on more
objects, call a method and assert over the state of it after doing it. The
different kind of testing and methodologies differ in the order in which they
perform these things, and the where they focus the test.
So far so good, but we need to test more scenarios to make sure that the test
didn't pass because we were lucky, but because the method is actually working.
In other words, we need to test for different values of x. Since we cannot test
every possible value, the common practice is to pick a few representative cases.
In our case, it's clear that we also need to test at least the following three
scenarios:
- x less than 0
- x equal to 0
- x equal to 1
We face an interesting case: what should we do if x is a negative number? The
Fibonacci function is only defined for numbers greater or equal than zero, so it
makes sense to throw an exception in that case. But how do we test that
behavior? We said a test will only pass if no exception is thrown during its
execution. One option would be to put the call to the
Fibonacci.Calculate in a try-catch block, calling the Assert.Fail or
throwing a new exception method in case the one we are waiting for is not
thrown, but a better option is to use the handy
ExpectedException attribute that will do just that
for us:
C#
[Test]
[ExpectedException(typeof(ArgumentException))]
public void
FibonacciOfNegativeNumberDoesNotExist()
{
Fibonacci.Calculate(-1);
}
VB
<Test()> _
<ExpectedException(GetType(ArgumentException))>
_
Public Sub
FibonacciOfNegativeNumberDoesNotExist()
Fibonacci.Calculate(-1)
End Sub
We run the test and we see it fails (but note that
FibonacciOfNumberGreaterThanOne keeps passing):
This is what we would expect, since we are not trowing any exception in the
Calculate method. Let's fix that:
C#
public static
int Calculate(int
x)
{
if (x < 0)
throw new
ArgumentException("x must be greater than or equal to zero");
return (x > 1) ? Calculate(x - 1) +
Calculate(x - 2) : x;
}
VB
Public Shared
Function Calculate(ByVal
x As Integer)
As Integer
If x < 0
Then
Throw New ArgumentException("x
must be greater than or equal to zero")
End
If
If x < 2
Then
Return x
End
If
Return Calculate(x - 1) + Calculate(x - 2)
End Function
We execute the tests again and all of them pass this time:
All that's left is to add tests for x equal to 0 and 1. But instead of writing a
test for each of them, we will use a powerful feature called row testing to
reduce the amount of coding we need to do. Here's the code:
C#
[Test]
[Row(0, 0)]
[Row(1, 1)]
public void
LowerBoundsTest(int x,
int Fibonacci)
{
Assert.AreEqual(Fibonacci.Calculate(x),
Fibonacci);
}
VB
<Test()> _
<Row(0, 0)> _
<Row(1, 1)> _
Public Sub
LowerBoundsTest(ByVal x As
Integer, ByVal
expectedFibonacciNumber
As Integer)
Assert.AreEqual(Fibonacci.Calculate(x), expectedFibonacciNumber)
End Sub
There are a few differences between this test and the previous we wrote:
- We applied some Row attributes
- This test method receives 2 parameters, just as
the number of items in each Row attribute
So what does this all mean? Gallio will create test instances for each Row
attribute, and will pass each value of it as a parameter to the test method (in
the same order by default), converting to the right type if necessary. We run
the tests in Icarus again and voilá!, they pass:
Row testing is one of the simplest cases of data-driven testing. As we will see
later, Gallio has powerful data-binding capabilities, supporting a heterogeneous
set of datasources and many ways to manipulate and scope them.
As the last thing in this chapter, we will see how to run the tests we created
with the TestDriven.NET add-in, which is one of
the most popular ways for developers to run tests in Visual Studio.
You can download TestDrive.NET from its website,
http://www.testdriven.net/. It's a commercial product, but at the time
of this writing there's a personal version of it.
After you have downloaded and installed TestDrive.NET, open the sample solution
again and right-click on the SimpleLibrary.Test project, as shown in the
screenshot:
In a few seconds you see this output:
The real benefit, however, of using the TestDriven.NET add-in comes when you
want to run individual tests:
In this case, the output window shows pretty useful information, like which test
instances were executed, the parameters they were passed and the outcome of each
one:
Also there is a link to the generated HTML report. If you Control-click it it
will be opened inside Visual Studio:
This report is always generated in a folder called Gallio.TDNetRunner within
your temporary files folder. Unfortunately the link is not displayed when
executing tests at the assembly level.
You now know pretty much everything that you need to get started. But keep
reading! There is still much more to discover in the next chapters.