But actually the tests were not clear enough and maintaining the fixtures was hard and time consuming as the amount of code duplication was high for any standard. New tests required us writing more code and they were not descriptive enough to work as a live documentation. Because of the way Fit uses inheritance, its fixture code is cumbersome and hard to maintain. Then we started search for other tools that allow to test the software with lower costs and we neglected Fitnesse for some time.
Recently I was pointed out the relatively new Slim protocol for using Fitnesse tests with Systems Under Test. The primary benefit of Slim is reducing the footprint of the framework in the SUT, sharing a single implementation of the table interpreter, and a Scenario table that can be called from other tables. It seemed to be that Slim FitNesse holds more promise for less effort and I decided to try it.
By the way, my current project is a web application, so the biggest part of our acceptance tests are tests against UI. As you know user interface has traditionally been hard to integrate into an automated test process. So trying to solve this task just lately we've added Selenium RC to our toolbox. Frankly speeking I don't like Selenium IDE and I am an antagonist of a recording and playing back tests in a browser. So the idea was to use Fitnesse to create some kind a Domain Specific Language to write and execute Selenium tests. And I can say that it is succeeded. Now I really like how we are writing and maintaining our user stories, how they look and feel, and its low price.
We can write test according to zero emission principle. I mean it is possible do not write any fitnesse fixture to run tests against our web application. We develop in Python, so we use a python port of the fitnesse slim server - WaferSlim and Selenium Python Client Driver to control pages of our application. So if you have setup fitnesse, WaferSlim, and Selenium you could write the next story without any coding except fitnesse.
|import|
|selenium|
|script|selenium;|${SLIM_HOST}|4444|iexplore|!-http://google.com-!|
|run|
|open|!-http://google.com/ncr-!|
|type;|q|selenium server|
|click|name=btnG|
|allow_native_xpath|true|
|wait_for_page_to_load|10000|
|check not|get_text|id=resultStats|BLANK|
So, it is great! The only thing I had to do to run it is an adopting the 'selenium' class in the selenium.py module. I mean that the 'selenium' class is not ready for a while to be using within Fitnesse and Slim. First of all - it necessary to rename this class into 'Selenium' instead of 'selenium'. For some reason fitnesse tries to find exactly that case-sensitive name. Next - in the '__init__' method you have to convert the 'port' parameter, that is given by fitnesse as a string, into int - self.port = int(port). And the last - rename the 'start' method, for example with 'run' or so. It is necessary because the 'start' keyword has a special meaning for fitnesse. This is it.
Now just imagine that you need to do the same thing, I mean call google's search from different user stories. In this case you have to move this code into python and make a function to be called from the different places on fitnesse. But wait! Fitnesse offers other way. Just look.
!|scenario|google search|string|
|start|selenium;|${SLIM_HOST}|4444|iexplore|!-http://google.com-!|
|run|
|open|!-http://google.com/ncr-!|
|type;|q|@string|
|click|name=btnG|
|allow_native_xpath|true|
|wait_for_page_to_load|10000|
|check not|get_text|id=resultStats|BLANK|
|script|
|google search|selenium server|
|script|
|google search|fitnesse slim|
I really like it! What about you? And one more great thing that I appreciate about fitnesse.
!|scenario|User is trying to search _ on google|string|
|google search|selenium server|
![ script
User is trying to search selenium server on google
]!
So, Fitnesse+SLIM+Selenium tandem is hightly recommended. Good lack in acceptance testing!