Scenario Tables for FitNesse
Posted by Uncle Bob on 08/04/2009
Scenario Tables are a very powerful new feature of FitNesse, allowing a whole new level of abstraction in the specification of tests. Scenario tables can be used on any page that uses the Slim test system.
One of the tests among the many acceptance tests for FitNesse itself ensures that certain operations require authentication. For example, if you declare a page to be read-locked, then you should not be able to read that page unless you have logged in.
Here is an example of an old-style FitNesse test that ensures that you can not save a page that is write-locked unless you log in.
Notice the detailed, step by step, programmerish nature of the test. 1. It creates a user with a password. 2. It creates a page that is write-locked. 3. It requests the page without any authentication and expects a 401. 4. It requests the page with bad authentication and expects a 401. 5. It requests the page with good authentication and expects a 303.
This test is not too hard to understand, and any good QA/BA ought to be able to grasp what it is doing. But it is certainly circuitous and indirect. Worse, this algorithm is repeated on a new page for each of fifteen other secure operations, creating a suite of very similar pages. In other words, lots of duplication.
In sweeping through the acceptance tests of FitNesse, I decided to use scenarios to simplify them. My first attempt at this was to adopt a Given/When/Then (BDD) approach. The same kind of approach that you might use with Cucumber of JBehave.
This test is much shorter, easier to read, and gets right to the point. It’s also much less programmerish since it doesn’t mention 401s or 303s. I was able to accomplish this by creating a set of scenarios that look something like the ones below. (They aren’t the exact ones, but you get the idea.)
All the programmerish stuff is hidden in the scenarios! That’s nice. If you look closely at the scenarios and substitute them into the test, you can see that the whole test simply turns into something very much like the original test.
Though this is better, we still have a lot of similar pages. The duplication has not been removed.
So then I added a third level of indirection. This one solves all the problems.
It’s hard to imagine a simpler test than this. Instead of a suite of sixteen different tests, I have one single test. The scenario is simply executed once of reach row of the “Operation is authenticated” table.
Here are the scenarios that allowed me to do this.
Once again, if you simply replace the scenarios in each row of the table, you’ll wind up with sixteen tests that look a lot like the original test. But now they are very direct, absurdly simple to read, and are virtually free of programmerish gobblety-gook.
Critics may rightly point out that you can get the same results by simply writing a ColumnFixture that interprets the final table. True, but then you put the burden of test-abstraction on the programmers. What is interesting about the scenario approach is that I was able to reduce the programmerish and highly duplicated tests into a single simple test table without writing any new fixtures!
In other words, programmers can supply a set of APIs, in the form of fixtures, and then competent test engineers can shape the tests appropriately with scenario tables that eventually call the low level fixture APIs while keeping the tests readable and free of duplication.
Comments
Marcel Popescu about 16 hours later:
Ok… I understood everything but the last example. What does “rss” mean? IOW, how is the “operation is authenticated” line interpreted compares to the way the “rss” line is interpreted?
Cory Foy about 16 hours later:
I agree with Marcel. I mean, I get that what you are saying is that each of those pages in FitNesse are required to be authenticated – but that’s only because I’ve been working in FitNesse for a long time. It would see that the last example is free from everything, including readability.
I also don’t like the tables you had to write to accomplish the GWT approach.
Scenario|It Should Be Readable By User|User|Password|Password|
It might help if the syntax told you that the second User and the second Password where incoming variables. Like:
Scenario Readable By User =user password =password
So when your eye is scanning it understands that those aren’t supposed to be read as normal english like everything else.
Doug Bradbury about 23 hours later:
Could you comment on test page organization? Where would you put the scenario tables so that they could be reused? In another page that is included at the top the test page?
Uncle Bob 2 days later:
FitNesse has many different operations that can be specified by the url. For example ?test ?suite ?refactor ?properties, etc. If you want to test MyPage you say http://myHost:myPort/MyPage?test.
These operations must be secure. The final table simply asserts that each operation, like ?rss, requires authentication.
As for test organization, there are special pages named “ScenarioLibrary” that are automatically included in every Slim Test Page. These pages are inherited just like SetUp and TearDown are inherited; except that whereas SetUp and TearDown are overridden, ScenarioLibrary is additive. You will inherit every single one of them up the parent chain.