In the comments on one of the previous blog entries in this series, Pekka Klärck pointed out that another great way to refactor a keyword-driven test to a data-driven is the usage of templates within Robot Framework. Before doing this, we will take a look at BDD style tests using given, when, and then. Following an ATDD approach does not make sense for the problem statement given, but I will at least scratch that topic during the reflection.
Some clean-up
Another feedback I got from Dale Emery suggests to extract the xpath entry to identify the costs in the keyword-driven test. So, we edit resource.txt in the data-driven tests to:
...
*** Variables ***
...
${COST_ITEM} xpath=//tr[td/div[@class='SubHead'] = 'COST']/td/span/font/b
*** Keywords ***
...
Calculated Cost Should Be [Arguments] ${expectedCost}
Click Button Submit
${actualCost} = Get Text ${COST_ITEM}
...
Thereby we can override the cost item once the user interface changes with a single change of that variable, or even change the value from the command line via an option while the new user interface is still under development. In a recent talk, Uncle Bob Martin uses the term “extract method until you drop” for good code. I use a similar term for acceptance tests here, but it’s “extract variable until you drop”. Taking a closer look on the resource.txt file now reveals that nearly all the variables are in one tiny place together. Just the title of the Parking Calculator is inline in the keywords, so we extract that one, too.
I will leave the same steps for the resource.txt file in the keyword-driven tests as an exercise to the reader. The resulting repository tree can be found here.
BDD style
Basically the BDD style is similar to keyword-driven tests. Let’s start with an easy one using Valet Parking. First, we create the direct BDD, and edit the valet.txt, similar to the layout we used for keyword-driven tests.
Usually the given, when, and then sections of a BDD style tests reflect the setup, execute, and verify steps of a three-step test. given ensures the preconditions, when executes the system under tests, and then checks the postconditions. Here is the first test, parking for less than five hours, that I came up with:
Less Than Five Hours
Given I want to use Valet Parking
When I park for less then five hours
Then the calculated Cost Should Be $ 12.00
Now, we need to evolve the keywords behind this. For the suite setup and teardown I used to open parkcalc and close the browser respectively as before. Now, we need to write the three keyword listed up in the first test together with these. I decide to put them directly into the resource.txt file, which I create for that purpose.
*** Settings ***
Documentation A resource file containing the ParkCalc app specific keywords and variables for BDD-style tests that create our own domain specific language. Also SeleniumLibrary itself is imported here so that tests only need to import this resource file.
Library SeleniumLibrary
*** Variables ***
${BROWSER} firefox
${DELAY} 0
${PARKCALC URL} http://adam.goucher.ca/parkcalc/
${COST_ITEM} xpath=//tr[td/div[@class='SubHead'] = 'COST']/td/span/font/b
${PAGE_TITLE} Parking Calculator
@{FOR_ONE_HOUR} 05/04/2010 12:00 AM 05/04/2010 01:00 AM
*** Keywords ***
Open ParkCalc
Open Browser ${PARKCALC URL} ${BROWSER}
Set Selenium Speed ${DELAY}
Title Should Be ${PAGE_TITLE}
Given I want to use [Arguments] ${lot}
Select From List Lot ${lot}
When I park for less then five hours
Entry And Exit Dates @{FOR_ONE_HOUR}
Entry And Exit Dates [Arguments] ${entryDate} ${entryTime} ${entryAmPm} ${exitDate} ${exitTime} ${exitAmPm}
Input Text EntryTime ${entryTime}
Select Radio Button EntryTimeAMPM ${entryAmPm}
Input Text EntryDate ${entryDate}
Input Text ExitTime ${exitTime}
Select Radio Button ExitTimeAMPM ${exitAmPm}
Input Text ExitDate ${exitDate}
Click Button Submit
Then the calculated costs should be [Arguments] ${cost}
${actual} = Get Text ${COST_ITEM}
Log Actual costs: ${actual}
Page Should Contain ${cost}
Running the tests, I can see that they pass. Check-in time. Here is the source for that.
Now, you may have noticed that I reused the parking durations as defined in the data-driven tests together with a mixture inspired from the keyword-driven tests. That is quite natural for a BDD-style test.
Continuing as before, I create similar tests in the same manner, thereby developing first the valet parking tests. While doing so, I notice that I could add some parameters to the keywords with the when prefix thereby getting rid of the duplication completely. This couples the duration variables more to the tests, but I feel that I may reuse them in other tests later, so I leave the durations in the resource file. Here are the final valet parking test cases:
Less Than Five Hours
Given I want to use Valet Parking
When I park @{FOR_ONE_HOUR}
Then the calculated costs should be $ 12.00
Exactly Five Hours
Given I want to use Valet Parking
When I park @{FOR_FIVE_HOURS}
Then the calculated costs should be $ 12.00
More Than Five Hours
Given I want to use Valet Parking
When I park @{FOR_SIX_HOURS}
Then the calculated costs should be $ 18.00
Multiple Days
Given I want to use Valet Parking
When I park @{FOR_FOUR_DAYS}
Then the calculated costs should be $ 72.00
and this is the resulting resource.txt content
*** Variables ***
...
@{FOR_ONE_HOUR} 05/04/2010 12:00 AM 05/04/2010 01:00 AM
@{FOR_FIVE_HOURS} 05/04/2010 12:00 AM 05/04/2010 05:00 AM
@{FOR_SIX_HOURS} 05/04/2010 12:00 AM 05/04/2010 06:00 AM
@{FOR_FOUR_DAYS} 05/04/2010 12:00 AM 05/08/2010 12:00 AM
*** Keywords ***
Open ParkCalc
Open Browser ${PARKCALC URL} ${BROWSER}
Set Selenium Speed ${DELAY}
Title Should Be ${PAGE_TITLE}
Given I want to use [Arguments] ${lot}
Select From List Lot ${lot}
When I park [Arguments] ${entryDate} ${entryTime} ${entryAmPm} ${exitDate} ${exitTime} ${exitAmPm}
Input Text EntryTime ${entryTime}
Select Radio Button EntryTimeAMPM ${entryAmPm}
Input Text EntryDate ${entryDate}
Input Text ExitTime ${exitTime}
Select Radio Button ExitTimeAMPM ${exitAmPm}
Input Text ExitDate ${exitDate}
Click Button Submit
Then the calculated costs should be [Arguments] ${cost}
${actual} = Get Text ${COST_ITEM}
Log Actual costs: ${actual}
Page Should Contain ${cost}
Running the tests, I can see that it’s time to check them in again. Here is the resulting tree.
Finally, I can continue to work on the other four parking lots in the same manner. This leads me further to this tree in the source repository.
One thought on “ParkCalc automation – BDD style tests”