Beautiful Code [123]
The first cell in the table specifies the name of the fixture class that will be used to process the table. For instance, Figure 6-1 shows a table that will be processed by the MarketEvaluation fixture. Figure 6-2 shows the same table after FIT has processed it; onscreen, the shaded cells would be red to show a validation failure.
Figure 6-1. HTML table displayed before FIT processing
Figure 6-2. HTML table displayed after FIT processing
The key idea behind FIT is that documents can serve as tests. You could, for instance, embed tables in a requirements document and run the document through FIT to see whether the behavior specified in those tables exists in your software. These documents with tables can be written directly in HTML, or they can be written in Microsoft Word or any other application that can save documents as HTML. Because a FIT fixture is just a piece of software, it can call any portion of an application you care to test, and make those calls at any level. It's all under your control as a programmer.
I won't spend any more time explaining FIT and its problem domain; there's more information on the FIT web site (http://fit.c2.com). But I do want to describe the design of FIT and some of the interesting choices it embodies.
The core of FIT is only three classes: Parse, Fixture, and TypeAdapter. Their fields and methods, and the relationships between them, are shown in Figure 6-3.
Figure 6-3. Relations among FIT classes
Let's walk through it.
In a nutshell, the Parse class represents the HTML of a document. The constructor of Parse accepts a string and recursively constructs a tree of Parse objects, knit together using the fields parts and more. Each Parse object represents some portion of the document: there's an individual Parse for each table, row, and cell.
The Fixture class traverses the tree of parses, and TypeAdapter converts testing values (numerics, dates, etc.) to text and back again. Fixtures talk to the application you are testing and mark individual cells red or green if a check passes or fails.
Most of the work in FIT happens in subclasses of the Fixture class. Fixtures define the format of the HTML tables they interpret. If you want to create a table that consists of, say, a series of commands to execute against your application, you use the predefined ActionFixture class. If you want to query your application for multiple results and compare them against a set of expected values, you use the RowFixture class. FIT provides these simple subclasses, but it also allows you to subclass Fixture yourself.
FIT is a useful framework. I use it often, and I'm continually amazed at what you can do with that core of three classes. Many frameworks would take three or four times as many classes to do the same amount of work.
Framework for Integrated Test: Beauty Through Fragility > The Challenge of Framework Design
6.2. The Challenge of Framework Design
OK, that's the architecture of FIT. Let's talk about what makes it different.
Framework design is tough. The hardest thing about it is that you have no control over code that uses your framework. Once you've published your framework's API, you can't change the signatures of particular methods or change their semantics without forcing some work on the users of the framework. And, typically, framework users do not like to revisit their code when they upgrade; they want complete backward-compatibility.
The traditional way of handling this problem is to adopt certain rules of thumb:
Be very careful about what you make public: control visibility to keep the published parts of the framework small.
Use interfaces.
Provide well-defined "hook points" that permit extensibility in the places where you intend it to occur.
Prevent extension in places where you don't want it to occur.
Some of these guidelines have been written down in various places,[] but, for