My First Tests (Part 2)

→ Return to Part 1.

8.

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 tested 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.

9.

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.

Add the following code in FibonacciTest.cs

[Test]
[ExpectedException(typeof(ArgumentOutOfRangeException))]
public void Fibonacci_of_negative_number_does_not_exist()
{
   Fibonacci.Calculate(-1);
}

Adding A Second Test

Return to Icarus. You will perhaps get a message indicating that a new version of the assembly under test was found. Run the tests again and see that the new test is failing. This is what we would expect, since we are not trowing any exception in the Calculate method.

The Second Test Fails

10.

Let's fix the broken test. Modify the code of the Calculate method as follows:

public static int Calculate(int x)
{
   if (x < 0)
      throw new ArgumentOutOfRangeException("x", "Must be greater than or equal to zero.");
 
   return (x > 1) ? Calculate(x - 1) + Calculate(x - 2) : x;
}

Build you solution and run the tests again. All of them pass now.

All Test Pass

11.

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:

[Test]
[Row(0, 0)]
[Row(1, 1)]
public void Lower_bounds(int x, int expectedResult)
{
   int result = Fibonacci.Calculate(x);
   Assert.AreEqual(expectedResult, result);
}

There are a few differences between this test and the previous we wrote.

  • We applied a Row attribute for each of the scenarios we want to test (two in this case)
  • 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 Tests Pass

Notice how the execution log reports actually 4 tests while only 3 test methods were written. 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.

12.

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 TestDriven.NET from its website, http://www.testdriven.net. It's a commercial product, but at the time of this writing there's a free personal version of it.

After you have downloaded and installed TestDriven.NET, open the sample solution again and right-click on the SimpleLibrary.Test project.

Running the tests with TestDriven.NET

In a few seconds you see this output:

TestDriven.NET output

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.

You know now pretty much everything you need to get started. But keep reading! There is still much more to discover.