Fitter Tutorial

Workflow

The typical workflow when using Fitter is to

  1. Write one or more test documents
  2. Write any fixtures required by the test documents.
  3. Run the tests

Whether you write your test documents before you write your fixtures is up to you. Those of us who have been using Fitter for a while have found that it helps to clarify the actual inputs and outputs of the fixtures that the test might need to use.

Writing Test Documents

Test documents are HTML or Word documents containing tables that identify the fixtures that need to be run. Test authors can use whatever editors they’re comfortable with to write and edit the documents. For HTML documents, any text editor can be used, but an editor that offers WYSIWYG editing might be easier than editing the raw HTML. For Word documents, an application like Microsoft Word is required. Microsoft Word can even edit HTML documents which is why Happier (the visual test runner) uses it, by default, to edit both Word and HTML documents.

Test documents can contain any text that helps the test author describe the functionality being exercised. All such text is ignored. The only parts of the test document that Fitter cares about are the tables. Tables are used to identify and run fixtures.

An example test document might look like this:

test1

The text above and the below the table is completely ignored by Fitter. The table isn’t formatted in any specific way, but it could have been formatted in order to make it more visually appealing. Fitter ignores all formatting and only cares about the structure and contents of the table.

After formatting the table to add a little style, it could look something like this:

test2

In that example, the distinct parts of the table that Fitter cares about are formatted differently to make it easier to talk about those parts.

As you can see, the first row of the table contains its “title”. In this case, the title is Tutorial.Math, Tutorial. This identifies what fixture this table will run. .NET developers should recognize this as containing a namespace name, class name, and assembly name. There are ways to make this prettier which we’ll go over later.

In the above example, the cells in the first row have been merged and the font size has been increased to make it stand it. This makes the first row look like a title to us humans, but all Fitter cares about is that the title be located in the first cell of the first row.

The remaining rows in the table indicate the data that the fixture identified by the title row accepts as input or provides as output.

The first column, containing the cells with the gray background, indicate the names of the inputs and the outputs. As you can see, the Math fixture accepts or provides three pieces of data. The names are A, B, and Sum.

To distinguish between the inputs and outputs, Fitter allows you to use a ? as the suffix of a name to mark the outputs. Based on the above example, you should be able to see that only one row, the row containing Sum?, is an output. The other two rows, A and B, specify inputs.

When the Math fixture runs, it will be given the value 1 for A and the value 2 for B. After it’s done, the value the fixture holds for Sum will be written to the table so that you could see what the result was.

After “running” the test document (which we’ll cover below), the result document might look like this:

result2

Notice how the previously empty cell in the second column of the last row (next to Sum?) now contains a value. The value it contains is colored light gray to indicate that it was not typed into the original document and was placed there by running the test.

You can no doubt tell that the calculated sum is correct, but wouldn’t it be more useful if the test runner could tell you if it was correct without forcing you to open the result document, look at the inputs, do the math in your head, and compare it to the output?

Instead of leaving the output cells empty, test authors can specify what outputs they expect by entering values in those cells. After a fixture runs, output values are either written into empty cells or compared against non-empty cells. If the comparison succeeds, the test passes. Otherwise, the test fails and the cell that contained an expected value that wasn’t equal to the actual value is marked to make it obvious why the test failed.

For example, adding an expected output to the previous test document might look like this:

test3

After running the test, the result document would look like this:

result3

The cell containing the expected value is colored green to indicate the actual output value matched the expected value.

Suppose the test had been modified to purposely fail like this:

test4

Running that test would result in this:

result4

This time, the cell containing the expected value is colored red and the actual value is inserted into it, next to the expected value, to help determine why the test failed.

You can extend this example in many different ways. Any number of inputs can be given to the fixtures that operate on them, producing any number of outputs. In the next section, we’ll see what it take to actually write the fixture run by the previous examples.

Writing Fixtures

Fixtures are the objects that contain the code that actually performs the work your test documents indicate with their tables.

Being objects, we need to define a class to use to construct the objects. You might have recognized the title of the table in the examples in the previous section looked like a fully-qualified .NET type name. The class identified by that name needs to be one that derives from Fitter.Fixture or one of its sub-classes.

The most commonly used sub-class of Fitter.Fixture is Fitter.OperationFixture. That’s the type of fixture we assumed exists in the previous section when writing the document.

Operation fixtures use the input values their given to perform operations. As a result, output values may (and usually are) be available for examining after the operation is performed.

Operation fixtures are simply classes that derive from Fitter.OperationFixture. That class, might look something like this:

using Fitter;

namespace Tutorial
{
    public class Math : OperationFixture
    {
    }
}

There’s not a lot going on in this class yet, but it’s a start.

Inputs to an operation fixture are supported by adding public fields to the fixture class. Properties and methods are also supported but fields are usually the simplest.

Adding the A and B inputs to the class might look like this:

using Fitter;

namespace Tutorial
{
    public class Math : OperationFixture
    {
	public int A;
	public int B;
    }
}

Our fixture is also expected to support an output named Sum. Outputs are added as public field (or properties or methods) just like inputs.

using Fitter;

namespace Tutorial
{
    public class Math : OperationFixture
    {
	public int A;
	public int B;
	public int Sum;
    }
}

There’s nothing required in the source to indicate which fields are inputs and which are outputs. This is why the test document uses ? suffixes on output fields. It is possible to use attributes on the fields to make it clear which fields are inputs and which are outputs, but it’s not necessary. Using those attributes will be covered later.

So far, the fixture doesn’t actually do anything. To get the fixture to execute code, we need to override the Operate method defined in its Fitter.OperationFixture base class.

The Operate method gets invoked after the input fields are written to on the object. It’s assumed that inside the Operate method, all output fields are assigned their resulting values. Once Operate is done, the output fields are read and used to either update the document or compared with the expected results in the test document.

Knowing this, we could add an Operate method to our Math fixture like this:

namespace Tutorial
{
    public class Math : OperationFixture
    {
	public int A;
	public int B;
	public int Sum;

	protected override void Operate()
	{
	    Sum = DomainModel.Math.Add(A, B);
	}
    }
}

For this example, it’s assumed that DomainModel.Math.Add is the method we’re actually testing. Notice how the A and B fields are used by passing them into the Add method. The return value of the Add method is then assigned to the Sum field which we think of as being an output.

Assuming the Add method works correctly, the results of running the test should appear as they did in the previous section.

This example is admittedly trivial, but it demonstrates the mechanics of getting data into and out of fixtures. Fixture authors can use whatever code necessary inside their Operate methods to perform their tests. Databases could be accessed, web services could be invoked, and domain models could be exercised. The only limit is your imagination.

Operation fixtures are just one kind of fixture. The other commonly used fixture type are query fixtures. Those are classes that derive from Fitter.QueryFixture. They have a different purpose and are implemented to be used differently, but learning about them will have to come later.

Running Tests

TODO: Show screenshots on how to use Happier to run the tests. Include showing what files to put in the folder (Fitter.dll, Happier.dll, the fixture assembly, and the test document). Also show to create a .fitterproj file to configure where tests and assemblies are located.