Several months back, however, I began wondering if there were other open source tools that could sustain our existing requirements, and in addition, provide a simpler solution for our non-technical users (business analysts, product managers, testers, and management). My research led me to several solutions that, I felt, might work out:
For reasons I won't delve into here, we opted for Cucumber. Specifically, we opted for the Cucumber + Cuke4Duke + Selenium solution. We went with Cuke4Duke primarily because our development team uses Java, and because we have several members of our team that are quite familiar with Java. Although the toolkit I opted for promised to help solve some of our issues, getting the various tools installed and configured proved to be much more of a challenge than I had expected - particularly, the Cuke4Duke component.
Further research led me to several articles that helped me piece the puzzle together1. Once I had our project "mavenized" (a term I often use to indicate a project has been built with Maven), per the information contained in reference 1, I went on to install the necessary gems using the mvn -Dcucumber.installGems=true cuke4duke:cucumber command outlined in references 1 and 2. Then, I set about meeting with our subject matter expert to collaborate on the various features and scenarios that would make up the initial sanity test. After putting together a handful of scenarios together, we implemented the Java code required to test our web application.
Although I have only worked with Cucumber for a short period of time, it's apparent to me that one of Cucumber's greatest strengths is the ease with which one can move from creating the features and scenarios, to building the step definitions, to implementing the underlying code that ties back to the application under test. And, since the features and scenarios are contained in simple text files, collaboration between technical and non-technical users is simplified - no need to learn a new tool, or familiarize yourself with a special markup language - the scenarios are plain text files that can be easily shared between team members using any editor. Too doggone simple. That is when the proverbial "light-bulb went off in my head". Suddenly, I felt enlightened and empowered at the same time.
So, with all that being said, here is a brief guide of what you will need to get Cucumber + Cuke4Duke + Selenium up and running. The recipe goes something like this
Ingredients
Maven 2.2.x - 1 prerequisite
Cucumber - 1 serving
Cuke4Duke - 1 serving
Selenium 2.0 - 1 serving (as of this writing, Selenium 2 is in its alpha phase)
Instructions
- Create a Maven project - we are currently using Eclipse to handle this. Essentially, create a project that contains the POM file outlined in reference 1.
- Add the following to the POM file's dependencies node in order to provide for Selenium support
<dependencies>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium</artifactId>
<version>2.0a6</version>
</dependency>
and add the following to the POM file's repositories node</dependencies>
<repositories>
<repository>
<id>selenium-repository</id> <url>http://selenium.googlecode.com/svn/repository/</url>
</repository></repositories>
and add the following to the POM file's cucumberArgs node
<cucumberArgs>
<cucumberArg>--require ${basedir}/target/test-classes</cucumberArg>
</cucumberArgs>
- Save the POM file. Saving the POM file should begin the process of downloading a number of Maven dependencies. Wait until those dependencies are downloaded, before moving on to the next step.
- Execute the following from the command line within the project's root directory (i.e., the POM file's location): mvn -Dcucumber.installGems=true cuke4duke:cucumber. This should install all the remaining dependencies, including the required gems needed to run Cucumber.
- Create a features directory under the project's root directory
- Execute the following command from the project's directory to test out your installation: mvn cuke4duke:cucumber -DcukeArgs="--help". If all went well, you should see Cucumber's help message.
Feature: For the love of cheese
In order to find information about cheese
As a cheese lover
I want the ability to search Google for anything related to cheese
Scenario: The search for cheese
Given I have accessed Google's home page
When I enter the keyword of "Cheese"
And click the Submit button
Then the page title returned should be "Cheese - Google Search"
Now, let's create the class file containing the necessary Selenium code - label it CheeseSteps.java and save it to src/test/java.
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.htmlunit.HtmlUnitDriver;
import cuke4duke.annotation.I18n.EN.Given;
import cuke4duke.annotation.I18n.EN.Then;
import cuke4duke.annotation.I18n.EN.When;
import static junit.framework.Assert.assertEquals;
public class CheeseSteps {
private WebDriver driver;
private WebElement element;
public CheeseSteps() {
// Create a new instance of the html unit driver
// Notice that the remainder of the code relies on the interface,
// not the implementation.
this.driver = new HtmlUnitDriver();
}
@Given("^I have accessed Google's home page$")
public void iHaveAccessedGooglesHomePage() {
// And now use this to visit Google
driver.get("http://www.google.com");
}
@When("^I enter the keyword of \"(.*)\"$")
public void iEnterTheKeyword(String keyword) {
// Find the text input element by its name
element = driver.findElement(By.name("q"));
// Enter something to search for
element.sendKeys(keyword);
}
@When("^click the Submit button$")
public void clickTheSubmitButton() {
// Now submit the form. WebDriver will find the form for us from the element
element.submit();
}
@Then("^the page title returned should be \"(.*)\"$")
public void thePageTitleReturned(String expectedResults) {
assertEquals(expectedResults, driver.getTitle());
}
}
Essentially, the above code wraps the WebDriver example within the noted Given/When/Then annotations supported by Cucumber. To see the test in action, from within the project's directory execute the following command: mvn clean integration-test
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.htmlunit.HtmlUnitDriver;
import cuke4duke.annotation.I18n.EN.Given;
import cuke4duke.annotation.I18n.EN.Then;
import cuke4duke.annotation.I18n.EN.When;
import static junit.framework.Assert.assertEquals;
public class CheeseSteps {
private WebDriver driver;
private WebElement element;
public CheeseSteps() {
// Create a new instance of the html unit driver
// Notice that the remainder of the code relies on the interface,
// not the implementation.
this.driver = new HtmlUnitDriver();
}
@Given("^I have accessed Google's home page$")
public void iHaveAccessedGooglesHomePage() {
// And now use this to visit Google
driver.get("http://www.google.com");
}
@When("^I enter the keyword of \"(.*)\"$")
public void iEnterTheKeyword(String keyword) {
// Find the text input element by its name
element = driver.findElement(By.name("q"));
// Enter something to search for
element.sendKeys(keyword);
}
@When("^click the Submit button$")
public void clickTheSubmitButton() {
// Now submit the form. WebDriver will find the form for us from the element
element.submit();
}
@Then("^the page title returned should be \"(.*)\"$")
public void thePageTitleReturned(String expectedResults) {
assertEquals(expectedResults, driver.getTitle());
}
}
Essentially, the above code wraps the WebDriver example within the noted Given/When/Then annotations supported by Cucumber. To see the test in action, from within the project's directory execute the following command: mvn clean integration-test