Since Selenium was introduced a few years back, it has continued to wow developers with how easily a user acceptance test can be knocked out– simply fire up an instance of a Selenium server in the background and then either write a table test or a RC style test– it’s that easy.
RC style testing is particularly powerful as you have full access to programming languages– for instance, with RC, you can write a functional web test in Java by leveraging a framework like JUnit or TestNG. But what’s often lacking with testing frameworks is a more natural way of expressing behavior– or indeed, scenarios and stories.
For instance, a user acceptance test is really a scenario– a user logs into a website, purchases an item, pays, and logs out. That was a sunny day scenario– there are other scenarios that deal with various other paths– user fails to pay, credit card was invalid, etc. All of these scenarios are logically a story– a story about buying something.
Using a standard scenario language, I can more specifically write a scenario (in a story regarding a website for race registrations) like so:
- given a user is on the race report page
- when someone enters a first name and last name in the race report form for someone who has signed up for a race
- then they should receive a list of all races that person has singed up for
That is a happy day scenario isn’t it? One particular negative path would be:
- given a user is on the race report page
- when someone enters a first name and last name in the race report form who hasn’t signed up for any races
- then they should receive a message indicating the person hasn’t signed up for any races
These scenarios can be easily created using easyb, which is a BDD framework for the Java platform– easyb leverages a domain specific language (or DSL) which supports the following syntax for scenarios:
scenario{
given "", {}
when "", {}
then "", {}
}
This DSL is highly flexible– you can chain phrases together with an and phrase and you can have multiple givens or whens or thens if you’d like. Also too, the scenario phrase isn’t required either.
The DSL makes the assumption that scenarios are in files that are either named YourNameStory.groovy or YourName.story– note that YourName is what ever you’d like.
Using easyb then, I can create a story file, which contains two scenarios– my file will be called RaceReport.story and I’ll start by defining two scenarios:
scenario "a valid person has been entered", {}
scenario "an invalid person has been entered", {}
Given that I plan to leverage Selenium, I’ll have to introduce a few new phrases– for instance, a then one that shuts down Selenium.
I’ll start the RC instance in a given phrase like so:
given "selenium is up and running", {
selenium = new DefaultSelenium("localhost",
4444, "*firefox", "http://acme.racing.net/greport")
selenium.start()
}
Note how I’m connecting to a server instance running on the same machine, which will utilize Firefox.
Next, I can chain two when clauses to simulate a user interacting with the report page.
when "filling out the person form with a first and last name", {
selenium.open("http://acme.racing.net/greport/personracereport.html")
selenium.type("fname", "Britney")
selenium.type("lname", "Smith")
}
and
when "the submit link has been clicked", {
selenium.click("submit")
}
My then clause then verifies that 4 race instances have been returned for my user– note how I’m able to use a nice Groovy for loop that uses a positional index to grab items from a list and from an XPath expression. Not bad, eh?
then "the report should have a list of races for that person", {
selenium.waitForPageToLoad("5000")
values = ["Mclean 1/2 Marathon", "Reston 5K", "Herndon 10K", "Leesburg 10K"]
for(i in 0..<values.size()){
selenium.getText("//table//tr[${(i+3)}]/td").shouldBeEqualTo values[i]
}
}
Lastly, I need to shut down selenium:
and
then "selenium should be shutdown", {
selenium.stop()
}
The entire first scenario looks like this once you put it all together:
scenario "a valid person has been entered", {
given "selenium is up and running", {
selenium = new DefaultSelenium("localhost",
4444, "*firefox", "http://acme.racing.net/greport")
selenium.start()
}
when "filling out the person form with a first and last name", {
selenium.open("http://acme.racing.net/greport/personracereport.html")
selenium.type("fname", "Britney")
selenium.type("lname", "Smith")
}
and
when "the submit link has been clicked", {
selenium.click("submit")
}
then "the report should have a list of races for that person", {
selenium.waitForPageToLoad("5000")
values = ["Mclean 1/2 Marathon", "Reston 5K", "Herndon 10K", "Leesburg 10K"]
for(i in 0..<values.size()){
selenium.getText("//table//tr[${(i+3)}]/td").shouldBeEqualTo values[i]
}
}
and
then "selenium should be shutdown", {
selenium.stop()
}
}
That’s pretty easy, don’t you think? Of course, my next step is to implement some additional scenarios, such as negative paths with an non-existing runner, etc.
When I run this via the easyb runner, I can get a story printout that looks something like this:
12 behavior steps executed successfully
scenario a valid person has been entered
given selenium is up and running on website
when filling out the person form with a first and last name
when the submit link has been clicked
then the report should have a list of races for that person
then selenium should be shutdown
scenario an invalid person has been entered
given selenium is up and running on website
when filling out the person form with a first and last name
when the submit link has been clicked
then the report should have a list of races for that person
then selenium should be shutdown
The scenarios are slight variations of one another, hence the report looks quite similar — each step is the same, just the data varies.
Functional web stories are a powerful mechanism to verify the proper behavior of web applications from a user’s standpoint. Combining a framework that supports stories and scenarios with Selenium yields an easy way to deliver software more quickly and collaboratively.

March 14th, 2008 at 1:23 pm
I liked the programs mentioned in your article but would like to suggest that you should increase the font of the programs so that people do not have difficulty in reading.
April 2nd, 2008 at 8:13 pm
[…] 0.8 is easyb’s bag The hip folks over at easyb.org have released version 0.8 of easyb. If you haven’t seen easyb yet, then you are in a for a real treat as easyb is the coolest thing since sliced bread, baby. As a BDD framework for the Java platform, easyb makes it super easy to craft executable documentation for software requirements by leveraging a flexible (and easy) story based domain specific language. […]
May 16th, 2008 at 8:57 am
[…] As an example of how fixtures can be copasetic, over on testearly.com, easyb was utilized in combination with Selenium to create a more human readable functional story. […]