A Different Approach to FitNesse “Macros”

My teammates Maykel Suarez, J.P. Erkelens and  Eddy Lara ought to be the ones blogging about this as they come up with these cool ideas, but I have the time and the inclination so I will. I hope they’ll read this and correct any errors I make.

I’ve used FitNesse since 2003 and obviously have not learned enough up to now!

We want our FitNesse tests to be DRY (Don’t repeat yourself), easy to maintain and easy to read and understand. Maykel and I were pairing on some FitNesse/SWAT tests this morning and found we needed the same test steps in more than one place. Maykel created this page under our “HelperMacro” area. Each FitNesse variable contains a SWAT test table.

!define NavigateToRatingScale (
!|SWAT |
|StimulateElement|Expression|

innerHtml:Performance Management;onclick:USGPM|onclick|A|
|StimulateElement|Expression|
innerHtml:Rating Scale |onclick|A|
)

!define NavigateToAddChangeRatingScale (${NavigateToRatingScale}
!|SWAT|
|StimulateElement|Expression|

innerHTML:Overall Review|onclick|A|
)

!define InputNumberOfLevels (
!|SWAT|
|SetElementAttribute|

Expression|Id:txtLevelNums|value |${NumberOfLevels}|INPUT|
|StimulateElement   |Expression|Id:txtLevelNums|
onchange|INPUT|
)

These are ‘macros’ defined as variables. Cool, huh? Notice that the second one, NavigateToAddChangeRatingScale, uses the first one, NavigateToRatingScale.

Here are examples of how we used these in test pages. First we include the page at the top of the test page;

!*> includes
!include -c <SuiteBookworms.HelperMacro.

RatingScales
*!

Then we can use whichever of the macros within RatingScales that we need at any time.

Navigate to add/change rating scale page
${

NavigateToAddChangeRatingScale}

When you view the test page in the browser, you see:
Browser rendering of navigate steps

It’s easy to understand what the test is doing, but we only have to maintain those steps on one page.

Here’s an example of setting the number of levels in a rating scale:

!define NumberOfLevels {5}
${InputNumberOfLevels}

In the browser view, this looks like:

Browser view of set rating scale steps

We have the kind of macros I’ve always been used to as well for example, a login macro:

{HomeUr}!*> login to $ with ${UserName} and ${Password}
!|SWAT|
|NavigateBrowser|${HomeUr\l}|
|SetElementAttribute|Id|ctl00_

Content_Login1_UserName|value|${UserName}|INPUT|
|SetElementAttribute|Id|ctl00_
Content_Login1_Password|value|${\Password}|INPUT|
|StimulateElement|Id|ctl00_
Content_Login1_LoginButton|onclick|INPUT|
*!

which are included in a test in the way to which I am accustomed:

!define UserName {hobbest}
!include <SuiteBookworms.HelperMacro.LoginMacro

I can’t articulate why I like the first, different approach, using variables to hold the macros, better than the way I’ve done it for years. It seems more streamlined to me, while retaining the ease of maintenance and understandability. Say sometimes you want to navigate to Page A, and other times you need to get to Page 2 which requires first going to Page A. If you’re including a bunch of one-line macros – one to navigate to Page A, one to navigate to Page 2 – your test gets real clunky looking.

Something Really Slick

Maykel, J.P. and Eddy used a similar technique so that a test could iterate through the same steps with different inputs each time. A variable is defined with a SWAT FitNesse table as its contents, including both a variable for the input value and a variable for the assert. Then it’s quick and easy to have multiple test cases using the same table. It took me a little while wo work out what they’re doing, but I love it.

!define AssertValidInputNumberOfLevels (
${InputNumberOfLevels}
!|SWAT|
|@AssertElement\${Exists}|

Expression|innerHtml:Invalid numeric value. Value should be a number from 1 to 99.;id:ctl00_errMsg|div |
)

This test expects an error message to come up, since 5.3 is an invalid value.

!define NumberOfLevels {5.3}
!define Exists {Exists}
${
AssertValidInputNumberOfLevels}

The next test expects that no error message will appear, as 42 is a valid value.

!define NumberOfLevels {42}
!define Exists {DoesNotExist}
${ AssertValidInputNumberOfLevel}

(there are several more of these with different values, some which expect an error message, some which expect no error message)

In the browser these look like this, so they’re perfectly easy for POs or anyone to read.

Slick way to use variable to iterate different inputs, expected results

Is this something everyone does and I just didn’t run across it before?

One comment on “A Different Approach to FitNesse “Macros”

  1. You’ll love Scenario tables from Slim. If you browse through http://fitnesse.org/FitNesse.SuiteAcceptanceTests you will notice that Bob introduced a “library” of Slim tables, that are regularly used for BDD like tests in the acceptance tests of FitNesse itself. In addition these include parameters and when executed you can dive into separate levels of abstractions in order to trace down the problem.

    (I assume you’ve already printed out the Cheat Sheet from FitNesse: http://fitnesse.org/FitNesse.UserGuide.QuickReferenceGuide ? It’s of great help.)

    Though I sense problems with these kind of approaches. There is no guarantee that if you make changes to the variable, you find all places to change and the like. In addition it makes editing the test pages a bit more thought-provoking. Sometimes I reminded on my shell-script days, where we included debug statements with each function name and parameter just to be able to get to know what happens in the shell scripts… I’m afraid of a similar drawback in FitNesse tests itself in the long run.

Leave a Reply

Your email address will not be published. Required fields are marked *