Testing in plain English

Having written this test, you might wonder why this is any better than using NUnit. We have written almost as much code as we would have to write for NUnit, and it is not any more readable to non-programmers than the NUnit test would be.

FitNesse is not just for unit testing. In fact, it is not intended for unit testing at all, although it can be quite good for describing functional tests. The primary target of FIT and FitNesse are acceptance tests — turning what the customer actually wants into tests and automating them. And yes, the table does not look any better than a NUnit test right now, but this is just the beginning.

One of the original goals of FIT was to enable non-technical users to collaborate on writing tests. Several syntax tricks and a bit of smart formatting can make test pages much more readable and closer to the English language than to C#. Here are a few tricks to start with.

Use names that are easy to read – FitNesse will find the correct .NET equivalent

When mapping tables to classes, properties, variables and methods, FitNesse does a case-insensitive search and ignores blanks. So, instead of:

|payoutPool|winningCombination|PoolPercentage?|PrizePool?|

we can write:

|Payout Pool|Winning Combination|Pool Percentage?|Prize Pool?|

The test looks much better on the screen, is easier to read, and splitting names into several words solves the problem of automatic CamelCase conversion into links.

Import namespaces and clean up table headers

To make the test class header simpler, remove the namespace, and import it using the Import table. Start the table with a single word: import. Then specify namespaces in the following rows.

!|import| 
|Tristan.Test|

We need to import the namespace only once for the entire page (actually, once for the entire test suite, which I'll explain later). We can even divide the class name into several words.

Replace repetitive values with arguments

The payout pool in your test is always the same, and repeating it in every table row just clutters up the screen. You can initialise it once for the entire table by using fixture arguments. Rather like the Main method of a console application, a fixture can have a number of optional string arguments, which are stored in a protected array Args. So we can change the class to read the payout pool from a fixture argument:

Tristan/test/TotalPoolValue.cs


12      public decimal? payoutPool;
13      public decimal PrizePool()
14      {
15        if (payoutPool == null) payoutPool = Decimal.Parse(Args[0]);
16        return wc.GetPrizePool(winningCombination, payoutPool.Value);
17      }

Specify arguments in the first row of the test table, after the class name.

[Tip]FitNesse cannot find the Import table — why?

The import command is, in fact, a special test table defined in fit.dll. Although the online documentation does not mention any specific preconditions for the import command, some versions of the .NET runner do not automatically include standard test classes. If FitNesse cannot find the import table, add a line containing

!path dotnet2/fit.dll

to the start of the page. This will make sure that the basic FIT library is included in the search for fixtures.

Talk to the customer

Generally, we can call our test classes and variables anything we like, so let's use this flexibility to make sure the customer also understands what is going on. Let's rename the test class to make it more understandable to the customers, for example, “Prize Distribution for Payout Pool”.

Use comments to describe tables

Any text outside of tables is just ignored. You can write explanations, include images, provide links to more information, or modify the test pages in any way you feel would improve understanding. This is one of the best features of FitNesse. Most testing frameworks do not allow for the provision of varied contextual information easily. So, let's add a short description of what this test does, to make it even clearer.

[Tip]What if I want to provide a table with additional details?

FitNesse executes all tables as tests, but there is a simple solution for providing non-test tables. Just put Comment as the table header and the table will be ignored. Comment is actually a test class that does nothing.

Use .NET formatting to make values easier to read

Counting those zeroes on the screen is really not fun. Big numbers are pretty ugly, but FitNesse uses .NET number formatting internally, which enables us to use separators for digit groups. For example, we can specify the pool size as 2,000,000 instead of 2000000.

Customer-friendly table

The end result in Figure 4.3, “This table looks much more customer-friendly” looks much like the original winnings table in Figure 4.1, “Last month's results”. If we could only insert the dollar sign, it would look exactly like the table. This can also be done easily, but let's leave the gold-plating for later (see Simplify verifications with a custom cell operator).

Figure 4.3. This table looks much more customer-friendly

This table looks much more customer-friendly

The clients and business analysts should have no problem understanding the results and verifying that the system actually does what they want. The business analysts can now use the page to discuss and review the requirements if and when the clients change their minds, and we can run automated tests and easily check what works and what is broken.