Acceptance Testing with FitNesse: Naming and Layout

Having dealt with Documentation and Infrastructure in the popular wiki-based acceptance-testing tool Fitnesse, Michael turns his attention to conventions and best-practices for naming and layout, in his continuing series of articles that represent the 'view from the trenches'.

Contents

FitNesse is a wiki-based framework for writing acceptance tests for software systems. If you are not familiar with FitNesse, Part 1 of this series walks through a complete .NET example from writing the test in your browser to writing the C# code-behind. The remaining articles in the series provide “tips from the trenches”, i.e. an accumulation of tips collected from intensive use of FitNesse on a daily basis to alleviate or avoid frustrations or quirks of FitNesse.

 

Part 1: FitNesse Introduction and Walkthrough

 

Part 2: Documentation and Infrastructure

 

Part 3: Naming and Layout

 

Part 4: Debugging, Control Flow, and Tracing

 

Part 5: Symbols, Variables, and Code-Behind Style

 

Part 6: Multiplicities and Comparisons

 

Part 7: Database Fixtures, Project Overview

Most sections in this article have references with actual hyperlinks to the FitNesse, fitSharp, or DbFit reference material. Some also have references to the sample test suite accompanying this series of articles, e.g. CleanCode.ConceptNotes.LayoutShowingEmbeddedNewlines. That path refers to a page on your FitNesse server. Thus if you are running on port 8080 on your local machine, the full URL to visit that page would be:
http://localhost:8080/CleanCode.ConceptNotes.LayoutShowingEmbeddedNewlines

Naming

Fixture Naming Pattern

In C# there are a variety of naming patterns you use when defining classes: somethingObserver, somethingProvider, somethingListener, etc.  That gives others in your team, or even you for that matter, some notion of the purpose of the class. Similarly, the fixtures you write (to sit between your FitNesse test pages and your system under test) should use the naming pattern somethingFixture. Not only does this give the benefit to the reader of knowing what the class is for, but also a benefit to the test writer. When a class uses that naming pattern, you can, and should, refer to it in a test without the Fixture suffix: Doing so makes the test more quickly understandable  to the reader. In the example below, on the right the purpose of this test table is obvious from its name: you intend to delete an incentive invoice.  On the left, however, it feels incongruous to  have the word ‘Fixture’ in there, needlessly exposing a piece of the inner machinery for no particularly good reason.

 

Less Clear Format

More Clear Format

1884-img59.jpg


!|DeleteIncentiveInvoiceFixture |
|Id         |            Result?|
|25         |                   |

!|DeleteIncentiveInvoice|
|Id         |    Result?|
|25         |           |

Naming Your API Elements

This next tip builds on the last technique for naming fixtures, but applies to all your API elements, both fixture classes as well as the fields, properties, or parameters within a fixture class that you expose as your API to FitNesse. Common C# coding convention recommends both your class names and your public elements begin with a capital letter. Beyond the first word, when you have multiple words in a  name there are different conventions that Visual Studio (or Resharper  for that matter) cannot enforce because it does not know where the word boundaries are. Some people like to Use_Underscores_Between_Words while others prefer RunTogetherWords and still others might use a combination of those. For your FitNesse Fixture classes you should use RunTogetherWords (more formally known as Pascal-casing) because, through the magic of FitNesse, you can use either the computer-oriented format (left) or the human-oriented format that allows whitespace between words (right) shown below. The choice is left to the reader!

 

Computer-oriented Format

Human-oriented Format

1884-img59.jpg


!|DeleteIncentiveInvoice            |
|InvoiceNumber|ClientName   |Result?|
|101          |Apex Holdings|       |

!|Delete Incentive Invoice           |
|Invoice Number|Client Name  |Result?|
|101           |Apex Holdings|       |

Naming Your Test Pages

When you create a FitNesse test page in your browser, the name of the test (or test page-they are the same) must be a valid WikiWord and must therefore:

  • Use Pascal casing, i.e. initial capital for each word
  • Use only letters or numbers
  • Have at least two capital letters in the word
  • Have no spaces between words

Thus the perfectly reasonable seeming names on the left are not allowed and must be coerced into a form like that shown on the right to pass muster. On the bright side, FitNesse gives you immediate feedback as you type the name as to whether your name is a valid or not.

 

Illegitimate Names

Legitimate Names

1884-img59.jpg

HTMLTest

myTestPage

e-LearningTest

Test2

HtmlTest

MyTestPage

ElearningTest

TestPage2

Rule 4 above might seem strange, given that FitNesse permits-nay, even enthusiastically encourages-whitespace in API element names, as shown in the previous tip. Well it is still doing that though it is not immediately obvious. When you are on a given test page, the test name is shown without whitespace. But if you traverse up to the parent of the test page, there it is shown with the words automatically separated out with white space.

 

On Each Test Page

On Parent Page

1884-img5A.jpg


HtmlTest
- - -
MyTestPage
- - -
ElearningTest
- - -
TestPage2

  • Html Test
  • My Test Page
  • Elearning Test
  • Test Page2


Layout

Embed Line Breaks in your Test Tables

All the test tables I have been using are deliberately narrow, perhaps just two or three columns and anything in their cells is relatively short. In actual practice, particularly if you start using database queries in a test, the contents of a single cell can get quite wide.

A test table, as you now know, consists of vertical bars delimiting cells. The contents of a single cell must be all on one line because FitNesse will otherwise stop looking for those vertical bars, get rather confused, and just decide it is not a test table after all.

Imagine that you have a database query that is typed on a single line that scrolls off the right edge of your browser, simulated here with this box being a proxy for your browser-if you could scroll horizontally you would see the query go on and on, both in the source and in the output:

1884-img59.jpg

!|query|SELECT ProductId, CurrentPrice, LastPrice, PriceIncreaseDate, TransactionC

1884-img5A.jpg

query

SELECT ProductId, CurrentPrice, LastPrice, PriceIncreaseDate, TransactionCode FROM d

But FitNesse provides a handy mechanism to create a literal zone. Put anything between these brackets !- anything -! and the contents are preserved exactly as is including, in particular, line breaks:

1884-img59.jpg


!|query|SELECT !-ProductId, CurrentPrice, LastPrice, PriceIncreaseDate, TranCode
FROM dbo.Incentives
WHERE CurrentPrice < LastPrice and CustId != 999-!|

1884-img5A.jpg

query


SELECT ProductId, CurrentPrice, LastPrice, PriceIncreaseDate, TranCode
FROM dbo.Incentives
WHERE CurrentPrice < LastPrice and CustId != 999

References: CleanCode.ConceptNotes.LayoutShowingEmbeddedNewlines

Order Your Columns Correctly

Inputs must appear before outputs! FitNesse processes columns sequentially from left to right. Thus calling the Result method before defining the Value property in the Echo fixture would result in unexpected output. In this example I am showing C# pseudocode rather than FitNesse test source code to make the issue obvious:

 

Outputs before Inputs (incorrect)

Inputs before Outputs (correct)

1884-img59.jpg

function Result { return Value; }

Result();

Value = “one”;


function Result { return Value; }

Value = “one”;

Result();


1884-img5A.jpg

Echo

Result?

Value


one expected
---------------
null actual

one

Echo

Value

Result?

one


one


 

References: CleanCode.ConceptNotes.OrderOfParametersMatters

Use Block Structure

Approach writing a test just as you would  writing code, i.e. do not have just one big blob of test tables. Unlike a unit test, where each test typically tests just one thing, an acceptance test in FitNesse may encompass a complex user story where, for instance, you may need to prepare bank data and customer data, validate preconditions before running a transaction, run the transaction and validate data from different database tables.

FitNesse provides these key syntactic elements to aid you:

Element

Token

Begin expanded block

!*

Begin collapsed block

!*>

Begin hidden block

!*<

Close any of these blocks

*!

Add horizontal rule

—-

This example shows how to use the three types of block elements:

1884-img59.jpg


'''Invisible block''' here to sanity check some preconditions:
!*< Sanity Check
Sanity Check here...
*!
'''Collapsed block''' here to set up data for the upcoming transaction test
!*> Insert Data
Insert data here...
*!
'''Expanded block''' here for the stuff you really care about in this test.
!* Do Transaction
Do Transaction here...
*!

1884-img5A.jpg

Invisible block here to sanity check some preconditions:

Collapsed block here to set up data for the upcoming transaction test.

Insert Data

 

Expanded block here for the stuff you really care about in this test.

Do Transaction

Do Transaction here…

The references below include two pages in my sample project illustrating good block style.

References: Line and Block Formatting,
CleanCode.ConceptNotes.LayoutShowingDifferentBlocks, CleanCode.DataBaseNotes.CrudOperations

Ensure Your Blocks are Blocks

A block must have a title in order to be recognized as a block.

 

Title Missing (incorrect)

Title Present (correct)

1884-img59.jpg


!*>
stuff here...
*!

!*> test block
stuff here...
*!

1884-img5A.jpg


!*>
stuff here...
*!

test block

 

Use Collapsed Blocks for Setup Pages

Generally you should collapse all your setup and teardown blocks. You can globally control whether they are expanded or collapsed with these two constants, typically defined on the root page. This affects SetUp, TearDown, SuiteSetUp, and SuiteTearDown pages.

!define COLLAPSE_SETUP {true}

!define COLLAPSE_TEARDOWN {true}

The latest version defaults to true for these, so you really only need to add these to your root page if you want to turn them off.

Reference: Global Variables

Keep Your Layout Tight

Compact your test vertically by eliminating blank lines between blocks. This is particularly helpful in compactly displaying a sequence of several closed blocks as shown.

 

Loose Vertical Space

Tight Vertical Space

1884-img59.jpg


!*> Variables
. . .
*!

!*> Namespaces
. . .
*!

!*> Connecting to the database
. . .
*!

!*> Check for debugging enabled
. . .
*!


!*> Variables
. . .
*!
!*> Namespaces
. . .
*!
!*> Connecting to the database
. . .
*!
!*> Check for debugging enabled
. . .
*!

1884-img5A.jpg

Variables

 

Namespaces

 

Connecting to the database

 

Check for debugging enabled

Variables

 

Namespaces

 

Connecting to the database

 

Check for debugging enabled

 

 

References: CleanCode.DataBaseNotes.CrudOperations

Deaden Portions of Your Test Page

Generally speaking, everything on your test page is active content-if FitNesse recognizes it as a valid token or construct it will engage with it, whether this is rendering text between vertical bars as a table and then executing it or embedding hyperlinks on any text in a WikiWord format, and so forth. There are several types of constructs that let you mask things from FitNesse.

Comment tables allow you to define a test table in the usual way and have it nicely formatted by FitNesse, but the content is not executed when you run the test page. Create a comment table with the Comment fixture:

1884-img59.jpg


!|Comment                     |
|Put anything|you want here   |
|and it will not be executed  |

1884-img5A.jpg

Comment

Put anything  

you want here

and it will not be executed 

Character escaping allows you to mark any amount of text to be used “as is”: no WikiWord evaluation (if the page exists as a reference it becomes a link; otherwise, it gets a [?] notation appended), line breaks (if present) are preserved, and the text itself appears just like its neighboring text.

1884-img59.jpg

Enter a !-LineOfText-! with character escaping to prevent

the [?] suffix from appearing. Here is OneWithoutTheEscape for comparison.

1884-img5A.jpg

Enter a LineOfText with character escaping to prevent

the [?] suffix from appearing. Here is OneWithoutTheEscape[?] for comparison.

Block escaping allows you to mark any amount of text to be formatted as a code sample, i.e. it is rendered in a fixed-width font, line breaks (if present are preserved), and there is always a line break before and after the block:

1884-img59.jpg

Regular text here.

Code: {{{Enter a code sample or other text in braces like this.}}}

1884-img5A.jpg

Regular text here.

Code:

Enter a code sample or other text in braces like this.

Reference: Comment Fixture, Character Formatting, Line & Block Formatting

More to Come…

There are many more aspects to review and issues to alleviate-stay tuned for Part 4!