Implement domain-specific tests using custom fixtures

Most of the time you can extend one of the standard fixtures to define the test workflow, such as ColumnFixture or DoFixture. However, if you find that no existing fixture covers exactly what you need, you might want to implement a completely new table type and use this to describe your domain tests.

For tables without a repetitive structure, extending TableFixture is probably the best solution (see Using existing forms for regression tables). For tables with a clearly repetitive form, it can be more efficient to extend Fixture and just hook in somewhere during the processing, depending on what you want to take over. For processing before the first data row gets executed (for example, connecting to a database specified in Fixture arguments), override DoRows and set up the environment before passing control to the DoRows method of the base class. If you want to process the entire row as a batch, instead of processing individual cells, then override DoRow.

Generally, try to reuse as much as you can. If columns map to object methods and fields in some way, extend BoundFixture (see Binding columns to class members ) and implement the correct binding. Try to reuse the cell handler mechanism, so that symbols and keywords work automatically for your fixture.

To iterate through a list of Parse objects, use the More property. Here is an example from Fixture source code:


1   private void AddRowToTable(Parse cells, Parse rows)
2   {
3   	rows.Last.More = new Parse("tr", null, cells, null);
4   }

Use the Parts property to traverse child elements of rows or tables. Although the property is called Parts, it actually points to the first child element, that is, the first cell in the row, not to a list of cells.


1   public virtual void DoRow(Parse row)
2   {
3   	DoCells(row.Parts);
4   }

Tables are represented by linked lists that can change during the test. For example, by changing the value of the More property, you can dynamically append cells and rows to the table during the test. Here is how RowFixture adds surplus rows:


1   private void AddRowToTable(Parse cells, Parse rows)
2   {
3   	rows.Last.More = new Parse("tr", null, cells, null);
4   }

Use the methods Right(Parse p) and Wrong(Parse p, String actualValue) to mark parts of the table as correct or wrong. You can use the Exception (Parse cell, Exception exception) method to signal an exception during processing. Exceptions are handled automatically if you reuse DoCell.

To read cell contents, use the Parse.Text property rather than Parse.Body, as this will strip all HTML tags and give you a pure string. To modify a cell, call Parse.AddToBody. This is how the symbol recall cell handler displays the current symbol value during processing. Consider using Fixture.Gray to format notes and annotations or Fixture.Label to format important messages, to keep your code consistent with other fixtures. For example, here is how RowFixture marks a row as missing:


1   private void MarkRowAsMissing(Parse row)
2   {
3        Parse cell = row.Parts;
4        cell.AddToBody(Label("missing"));
5        Wrong(cell);
6   }