Behaviour Driven Development is the keyword when we’re talking about test scenarios written in an ubiquitous language, strong interaction with stakeholders, product owners or testers and well described, common understandable test scenarios.
The popular JBehave framework is our tool of choice here and allows us to decouple our test stories from the test classes, offers an integration for web tests using Selenium and finally there’s a helpful Maven plugin for JBehave, too.
After a short excursion into the principles of Behaviour Driven Development we’re going to write and implement test stories for simple acceptance tests and web tests using selenium.
Prerequisites
We don’t need much for the following tutorial .. just be sure to have a valid installation of Java 6 and Apache Maven .. otherwise install both from the following sources..
A short introduction into BDD
Behaviour Driven Development (BDD) is an agile software development technique that enhances the paradigm of Test Driven Development (TDD) and Acceptance Tests and encourages the collaboration between developers, quality assurance, domain experts and stakeholders.
Dan North described BDD in 2009 as (source):
“BDD is a second-generation, outside-in, pull-based, multiple-stakeholder, multiple-scale, high-automation, agile methodology. It describes a cycle of interactions with well-defined outputs, resulting in the delivery of working, tested software that matters.”
Our basic unit to encapsule a set of features is a story. Acceptance criteria are a part of the story and lead to the definition of done.
Following the structure proposed by Dan North in his article “http://dannorth.net/whats-in-a-story/%20[What’s in a story?]” a valid template for a user story would be like this:
Title (one line describing the story)
Narrative:
As a [role]
I want [feature]
So that [benefit]
Acceptance Criteria: (presented as Scenarios)
Scenario 1: Title
Given [context]
And [some more context]...
When [event]
Then [outcome]
And [another outcome]...
Scenario 2: ...
The title should describe an activity e.g. “Customer creates an account” and gives us a point what should be done here.
The narrative should describe roles, goals and the motivation or business value. A common notation is “as a I want so that “.
The scenario’s title should describe what is special about the scenario and should be linked to the user story’s title without repeating it.
A single scenario is described by given initial states, events and outcomes – it is common to use the given/when/then notation here.
If you want to get some more details, please take a look at the chapter “Resources” and the BDD resources listed there, especially Dan North’s Blog and Behaviour-Driven.org offer a lot of useful information.
Setting up a test project
First we need a project to put our test scenarios and testable code in .. Maven to the rescue..
-
We’re creating a new simple Maven project via IDE+Maven plugin or by console:
mvn archetype:generate
-
In the next step we do what we always do: Setting the source/target level to Java 6, the encoding to UTF-8 and adding some dependencies .. for now your pom.xml should look like this one
<?xml version="1.0"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.hascode.tutorial</groupId> <artifactId>jbehave-bdd-tutorial</artifactId> <version>0.0.1-SNAPSHOT</version> <name>hasCode.com jbehave BDD tutorial</name> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <jbehave.core.version>3.3.2</jbehave.core.version> </properties> <dependencies> <dependency> <groupId>org.jbehave</groupId> <artifactId>jbehave-core</artifactId> <version>${jbehave.core.version}</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.6</source> <target>1.6</target> </configuration> </plugin> </plugins> </build> </project>
The first test story
-
Now we need some classes for the test, add them in src/main/java and the package com.hascode.tutorial
package com.hascode.tutorial; public class Product { private String name; /** * @return the name */ public String getName() { return name; } /** * @param name * the name to set */ public void setName(String name) { this.name = name; } }
package com.hascode.tutorial; public class User { private String name; /** * @return the name */ public String getName() { return name; } /** * @param name * the name to set */ public void setName(String name) { this.name = name; } }
package com.hascode.tutorial; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; public class ShoppingCart { private final Map<User, List<Product>> entries = new HashMap<User, List<Product>>(); public void add(final User user, final Product product) { List<Product> purchases; if (entries.containsKey(user)) { purchases = entries.get(user); } else { purchases = new ArrayList<Product>(); } purchases.add(product); entries.put(user, purchases); } public List<Product> getProductsByUser(final User user) { return entries.get(user); } }
-
Also we should define a story for the test in a file named add_product_to_shopping_cart.story in src/main/resources/com/hascode/tutorial
Scenario: When a user adds a product to the shopping cart, the product should be included in the user's shopping cart. Given a user Given a shopping cart Given a product When the user adds the product to the shopping cart Then the product must be included in the list of the shoppingcart's entries
-
Finally we’re adding the test class and mapping the fields to the grammar used in the story
package com.hascode.tutorial; import java.util.List; import org.jbehave.core.annotations.Given; import org.jbehave.core.annotations.Then; import org.jbehave.core.annotations.When; import org.jbehave.core.configuration.Configuration; import org.jbehave.core.configuration.MostUsefulConfiguration; import org.jbehave.core.io.LoadFromClasspath; import org.jbehave.core.junit.JUnitStory; import org.jbehave.core.reporters.Format; import org.jbehave.core.reporters.StoryReporterBuilder; import org.jbehave.core.steps.CandidateSteps; import org.jbehave.core.steps.InstanceStepsFactory; import org.junit.Assert; import org.junit.Test; public class AddProductToShoppingCart extends JUnitStory { private User user; private ShoppingCart shoppingCart; private Product product; @Given("a user") public void aUser() { user = new User(); } @Given("a shopping cart") public void aShoppingCart() { shoppingCart = new ShoppingCart(); } @Given("a product") public void aProduct() { product = new Product(); product.setName("Coffee"); } @When("the user adds the product to the shopping cart") public void userAddsProductToShoppingCart() { shoppingCart.add(user, product); } @Then("the product must be included in the list of the shoppingcart's entries") public void productMustBeListed() { List<Product> entries = shoppingCart.getProductsByUser(user); Assert.assertTrue(entries.contains(product)); } @Override public Configuration configuration() { return new MostUsefulConfiguration().useStoryLoader(new LoadFromClasspath(getClass().getClassLoader())).useStoryReporterBuilder(new StoryReporterBuilder().withFormats(Format.CONSOLE)); } @Override public List<CandidateSteps> candidateSteps() { return new InstanceStepsFactory(configuration(), this).createCandidateSteps(); } @Override @Test public void run() throws Throwable { super.run(); } }
-
Running the unit test produces the following output
Processing system properties {} (BeforeStories) Using 1 threads Running story com/hascode/tutorial/add_product_to_shopping_cart.story (com/hascode/tutorial/add_product_to_shopping_cart.story) Scenario: When a user adds a product to the shopping cart, the product should be included in the user's shopping cart. Given a user Given a shopping cart Given a product When the user adds the product to the shopping cart Then the product must be included in the list of the shoppingcart's entries (AfterStories) Generating reports view to '/var/project/jbehave-tutorial/target/jbehave' using formats '[stats, console, txt]' and view properties '{defaultFormats=stats, decorateNonHtml=true, viewDirectory=view, decorated=ftl/jbehave-report-decorated.ftl, reports=ftl/jbehave-reports-with-totals.ftl, maps=ftl/jbehave-maps.ftl, navigator=ftl/jbehave-navigator.ftl, views=ftl/jbehave-views.ftl, nonDecorated=ftl/jbehave-report-non-decorated.ftl}' Reports view generated with 3 stories (of which 0 pending) containing 1 scenarios (of which 0 failed and 0 pending)
Passing parameters from the story to the test
In the following test scenario we’re going to pass variables from the story to the test class …
-
First we’re adding a new class needed for our tests named UserDao in src/main/resources/com/hascode/tutorial
package com.hascode.tutorial; import java.util.HashSet; import java.util.Set; public class UserDao { private final Set<User> users = new HashSet<User>(); public void save(final User user) { users.add(user); } public Set<User> findAll() { return users; } }
-
The next we’re creating a new test story in a file named add_user_to_repository.story in src/test/resources/com/hascode/tutorial
Scenario: When users are added to the repository they must be found afterwards in the repository Given a user repository When the user adds 3 users to the user repository Then the user repository must contain 3 users
-
Also we’re creating a new test file named AddUserToRepository in src/main/java/com/hascode/tutorial
package com.hascode.tutorial; import java.util.HashSet; import java.util.List; import java.util.Set; import junit.framework.Assert; import org.jbehave.core.annotations.Given; import org.jbehave.core.annotations.Then; import org.jbehave.core.annotations.When; import org.jbehave.core.configuration.Configuration; import org.jbehave.core.configuration.MostUsefulConfiguration; import org.jbehave.core.io.LoadFromClasspath; import org.jbehave.core.junit.JUnitStory; import org.jbehave.core.reporters.Format; import org.jbehave.core.reporters.StoryReporterBuilder; import org.jbehave.core.steps.CandidateSteps; import org.jbehave.core.steps.InstanceStepsFactory; import org.junit.Test; public class AddUserToRepository extends JUnitStory { private final Set<User> users = new HashSet<User>(); private UserDao userDao; @Given("$amount products") public void someProducts(final int amount) { for (int i = 0; i < amount; i++) { final User user = new User(); user.setName("user " + i); users.add(user); } } @Given("a user repository") public void aUserRepository() { userDao = new UserDao(); } @When("When the user adds $amount users to the user repository") public void userAddsUsersToRepository(final int amount) { for (final User user : users) { userDao.save(user); } } @Then("Then the user repository must contain $amount users") public void productMustBeListed(final int amount) { Assert.assertEquals(amount, userDao.findAll().size()); } @Override public Configuration configuration() { return new MostUsefulConfiguration().useStoryLoader(new LoadFromClasspath(getClass().getClassLoader())).useStoryReporterBuilder(new StoryReporterBuilder().withFormats(Format.CONSOLE)); } @Override public List<CandidateSteps> candidateSteps() { return new InstanceStepsFactory(configuration(), this).createCandidateSteps(); } @Override @Test public void run() throws Throwable { super.run(); } }
-
The test produces the following output
Processing system properties {} (BeforeStories) Using 1 threads Running story com/hascode/tutorial/add_user_to_repository.story (com/hascode/tutorial/add_user_to_repository.story) Scenario: When users are added to the repository they must be found afterwards in the repository Given a user repository When the user adds 3 users to the user repository Then the user repository must contain 3 users (AfterStories) Generating reports view to '/var/project/jbehave-tutorial/target/jbehave' using formats '[console]' and view properties '{defaultFormats=stats, decorateNonHtml=true, viewDirectory=view, decorated=ftl/jbehave-report-decorated.ftl, reports=ftl/jbehave-reports-with-totals.ftl, maps=ftl/jbehave-maps.ftl, navigator=ftl/jbehave-navigator.ftl, views=ftl/jbehave-views.ftl, nonDecorated=ftl/jbehave-report-non-decorated.ftl}' Reports view generated with 3 stories (of which 0 pending) containing 1 scenarios (of which 0 failed and 0 pending)
Using the WebRunner
The WebRunner offers a nice web interface to control JBehave and modify your test scenarios …
-
Add the directory for the web application data
mkdir -p src/main/webapp/WEB-INF
-
Add the web.xml to the WEB-INF directory
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5"> <display-name>hasCode.com - JBehave WebRunner Example</display-name> <servlet> <servlet-name>wicket</servlet-name> <servlet-class>org.apache.wicket.protocol.http.WicketServlet</servlet-class> <init-param> <param-name>applicationClassName</param-name> <param-value>com.hascode.tutorial.runner.TutorialRunnerApplication</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>wicket</servlet-name> <url-pattern>/*</url-pattern> </servlet-mapping> </web-app>
-
Create a runner where the candidate steps are registered named TutorialRunnerApplication
package com.hascode.tutorial.runner; import java.util.List; import org.jbehave.core.steps.CandidateSteps; import org.jbehave.core.steps.InstanceStepsFactory; import org.jbehave.web.runner.wicket.WebRunnerApplication; import com.hascode.tutorial.AddUserToRepository; public class TutorialRunnerApplication extends WebRunnerApplication { @Override protected List<CandidateSteps> candidateSteps() { return new InstanceStepsFactory(configuration(), AddUserToRepository.class).createCandidateSteps(); } }
-
Change the project to create a war archive, add dependencies for the JBehave WebRunner and configure the Jetty Maven Plugin – my pom.xml now looks like this one
<?xml version="1.0"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.hascode.tutorial</groupId> <artifactId>jbehave-bdd-tutorial</artifactId> <version>0.0.1-SNAPSHOT</version> <name>hasCode.com jbehave BDD tutorial</name> <packaging>war</packaging> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <jbehave.core.version>3.3.2</jbehave.core.version> <jbehave.webapp.name>jbehave-webapprunner</jbehave.webapp.name> </properties> <dependencies> <dependency> <groupId>org.jbehave</groupId> <artifactId>jbehave-core</artifactId> <version>${jbehave.core.version}</version> </dependency> <dependency> <groupId>org.jbehave.web</groupId> <artifactId>jbehave-web-runner</artifactId> <version>${jbehave.core.version}</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.6</source> <target>1.6</target> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-dependency-plugin</artifactId> <executions> <execution> <id>unpack-resources</id> <phase>process-resources</phase> <goals> <goal>unpack</goal> </goals> <configuration> <outputDirectory>${project.build.directory}/resources</outputDirectory> <overWriteReleases>true</overWriteReleases> <overWriteSnapshots>true</overWriteSnapshots> <excludes>**/*.class</excludes> <artifactItems> <artifactItem> <groupId>org.jbehave.web</groupId> <artifactId>jbehave-web-runner</artifactId> <version>${jbehave.core.version}</version> </artifactItem> </artifactItems> </configuration> </execution> </executions> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-resources-plugin</artifactId> <executions> <execution> <id>copy-custom-resources</id> <phase>process-resources</phase> <goals> <goal>copy-resources</goal> </goals> <configuration> <outputDirectory>${project.build.directory}/resources</outputDirectory> <overwrite>true</overwrite> <resources> <resource> <directory>${basedir}/src/main/webapp</directory> </resource> </resources> </configuration> </execution> </executions> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-war-plugin</artifactId> <configuration> <webResources> <resource> <directory>${project.build.directory}/resources</directory> </resource> </webResources> </configuration> </plugin> <plugin> <groupId>org.mortbay.jetty</groupId> <artifactId>jetty-maven-plugin</artifactId> <configuration> <webAppConfig> <contextPath>/${jbehave.webapp.name}</contextPath> </webAppConfig> <webApp>${project.build.directory}/${jbehave.webapp.name}.war</webApp> </configuration> </plugin> </plugins> </build> </project>
-
Run the application with an embedded Jetty Webserver
mvn jetty:run
-
Now you’re able open the WebRunner application in your browser at the following URL: http://localhost:8080/jbehave-webapprunner/home
-
You’re now able to play around .. take a look at the screenshots below
Home
Datafiles
Find Steps
Run Stories
Testing a Web Application
Now we want to test a web site .. let’s say a popular search engine (but please do not spam them! :)
-
First we’re adding some dependencies to our pom.xml .. the dependency for selenium server depends on if you want to start an embedded selenium server in your tests or you’re using an existing standalone server
<dependency> <groupId>org.seleniumhq.selenium.client-drivers</groupId> <artifactId>selenium-java-client-driver</artifactId> <version>1.0.2</version> </dependency> <!-- only needed if you don't want to use a standalone selenium server --> <dependency> <groupId>org.openqa.selenium.server</groupId> <artifactId>selenium-server</artifactId> <version>1.0-20081010.060147</version> </dependency>
-
Next our test story in a file named search_popular_search_engine.story
Scenario: Search for the hascode.com website on Google Given The Google homepage When I search for "site:hascode.com" Then the text "hasCode.com » 2011 » March" is present When I click the link "hasCode.com" Then the text "Recent Articles" is present And the page's URL should be "https://www.hascode.com/"
-
Furthermore we’re defining our steps in the class SearchPopularSearchEngineSteps
package com.hascode.tutorial; import static org.hamcrest.CoreMatchers.is; import static org.junit.Assert.assertThat; import static org.junit.matchers.JUnitMatchers.containsString; import org.jbehave.core.annotations.Given; import org.jbehave.core.annotations.Then; import org.jbehave.core.annotations.When; import org.jbehave.web.selenium.SeleniumSteps; import com.thoughtworks.selenium.Selenium; public class SearchPopularSearchEngineSteps extends SeleniumSteps { private final String pageLoadTimeout = "6000"; public SearchPopularSearchEngineSteps(final Selenium selenium) { super(selenium); } @Given("The Google homepage") public void theGoogleHomepage() { selenium.open("/"); } @When("I search for \"$term\"") public void searchForTerm(final String term) throws InterruptedException { selenium.type("q", term); selenium.click("btnG"); Thread.sleep(4000l); // ugly } @Then("the text \"$textFragment\" is present") public void shouldSee(final String textFragment) { assertThat(selenium.getBodyText(), containsString(textFragment)); } @When("I click the link \"$linkText\"") public void followLinkWithText(final String linkText) { selenium.click("link=" + linkText); selenium.waitForPageToLoad(pageLoadTimeout); } @Then("the page's URL should be \"$url\"") public void pageURLShouldBe(final String url) { assertThat(selenium.getLocation(), is(url)); } }
-
Finally we’re putting it all together in the class SearchPopularSearchEngine
package com.hascode.tutorial; import java.util.Arrays; import java.util.List; import org.jbehave.core.Embeddable; import org.jbehave.core.configuration.Configuration; import org.jbehave.core.io.CodeLocations; import org.jbehave.core.io.LoadFromClasspath; import org.jbehave.core.io.StoryFinder; import org.jbehave.core.junit.JUnitStories; import org.jbehave.core.reporters.Format; import org.jbehave.core.reporters.StoryReporterBuilder; import org.jbehave.core.steps.CandidateSteps; import org.jbehave.core.steps.InstanceStepsFactory; import org.jbehave.core.steps.SilentStepMonitor; import org.jbehave.web.selenium.SeleniumConfiguration; import org.jbehave.web.selenium.SeleniumContext; import org.jbehave.web.selenium.SeleniumStepMonitor; import org.junit.Before; import org.junit.Test; import com.thoughtworks.selenium.DefaultSelenium; import com.thoughtworks.selenium.Selenium; public class SearchPopularSearchEngine extends JUnitStories { private final Selenium selenium = new DefaultSelenium("127.0.0.1", 4444, "*chrome", "http://www.google.com/"); private final SeleniumContext seleniumContext = new SeleniumContext(); @Override public Configuration configuration() { Class<? extends Embeddable> embeddableClass = this.getClass(); return new SeleniumConfiguration().useSelenium(selenium).useSeleniumContext(seleniumContext).useStepMonitor(new SeleniumStepMonitor(selenium, seleniumContext, new SilentStepMonitor())) .useStoryLoader(new LoadFromClasspath(embeddableClass)).useStoryReporterBuilder(new StoryReporterBuilder().withFormats(Format.CONSOLE)); } @Override public List<CandidateSteps> candidateSteps() { return new InstanceStepsFactory(configuration(), new SearchPopularSearchEngineSteps(selenium)).createCandidateSteps(); } @Before public void setUp() throws Exception { selenium.start(); } @Override @Test public void run() throws Throwable { super.run(); } @Override protected List<String> storyPaths() { return new StoryFinder().findPaths(CodeLocations.codeLocationFromClass(this.getClass()).getFile(), Arrays.asList("**/search_popular_search_engine.story"), null); } }
The console output should display the following information
(BeforeStories)
Using 1 threads
Running story com/hascode/tutorial/search_popular_search_engine.story
(com/hascode/tutorial/search_popular_search_engine.story)
Scenario: Search for the hascode.com website on Google
Given The Google homepage
When I search for "site:hascode.com"
Then the text "hasCode.com » 2011 » March" is present
When I click the link "hasCode.com"
Then the text "Recent Articles" is present
And the page's URL should be "https://www.hascode.com/"
The Selenium server logs could look like this one
22:10:49.548 INFO - Command request: getNewBrowserSession[*firefox, http://www.google.com, ] on session null
22:10:49.548 INFO - creating new remote session
22:10:49.766 INFO - Allocated session adbf7bd6cfc040b8ad3aeb634a37172b for http://www.google.com, launching...
22:10:49.872 INFO - Preparing Firefox profile...
22:10:52.518 INFO - Launching Firefox...
22:10:55.172 INFO - Got result: OK,adbf7bd6cfc040b8ad3aeb634a37172b on session adbf7bd6cfc040b8ad3aeb634a37172b
22:10:55.586 INFO - Command request: setContext[<b></b><br/>Given The Google homepage, ] on session adbf7bd6cfc040b8ad3aeb634a37172b
22:10:55.610 INFO - Got result: OK on session adbf7bd6cfc040b8ad3aeb634a37172b
22:10:55.612 INFO - Command request: open[http://www.google.com/, ] on session adbf7bd6cfc040b8ad3aeb634a37172b
22:10:56.245 INFO - Got result: OK on session adbf7bd6cfc040b8ad3aeb634a37172b
22:10:56.250 INFO - Command request: waitForPageToLoad[7000, ] on session adbf7bd6cfc040b8ad3aeb634a37172b
22:10:56.257 INFO - Got result: OK on session adbf7bd6cfc040b8ad3aeb634a37172b
22:10:56.260 INFO - Command request: setContext[<b></b><br/>When I search for "site:hascode.com", ] on session adbf7bd6cfc040b8ad3aeb634a37172b
22:10:56.275 INFO - Got result: OK on session adbf7bd6cfc040b8ad3aeb634a37172b
22:10:56.276 INFO - Command request: type[q, site:hascode.com] on session adbf7bd6cfc040b8ad3aeb634a37172b
22:10:56.295 INFO - Got result: OK on session adbf7bd6cfc040b8ad3aeb634a37172b
22:10:56.297 INFO - Command request: click[btnG, ] on session adbf7bd6cfc040b8ad3aeb634a37172b
22:10:56.323 INFO - Got result: OK on session adbf7bd6cfc040b8ad3aeb634a37172b
22:10:56.325 INFO - Command request: waitForPageToLoad[7000, ] on session adbf7bd6cfc040b8ad3aeb634a37172b
22:11:03.345 INFO - Got result: Timed out after 7000ms on session adbf7bd6cfc040b8ad3aeb634a37172b
22:11:03.367 INFO - Command request: testComplete[, ] on session adbf7bd6cfc040b8ad3aeb634a37172b
22:11:03.367 INFO - Killing Firefox...
22:11:03.447 INFO - Got result: OK on session adbf7bd6cfc040b8ad3aeb634a37172b
The JBehave Maven Plugin
The JBehave Maven Plugin allows you to access the Embedder functionality using Maven goals:
For more detailed information, take a look at the plugin’s documentation.
Sources Download
I have put the source from this tutorial on my GitHub repository – download it there or check it out using Git:
git clone https://github.com/hascode/jbehave-tutorial.git
Troubleshooting
-
“com.thoughtworks.selenium.SeleniumException: ERROR Server Exception: sessionId should not be null; has this session been started yet?” – ensure that the firefox binary is in your path .. e.g. export PATH=$PATH:/usr/lib/dir-to-firefox/. Another way to specify where your browser is located to define in in the selenium instance .. e.g.: selenium = new DefaultSelenium(“127.0.0.1″, 4444, “*chrome /path/to-your-browser”, “http://www.google.de/”);
-
Elements not found in selenium – ensure that the page is loaded .. use waitForPageToLoad() , waitForCondition() or waitForPopup() .. ajax calls are a problem here and Thread.sleep() is a dirty hack .. but there are workarounds on the internet.
Alternative: Cucumber for Java and Java EE
If you’re interested in an alternative please feel free to have a look at the following article of mine: “BDD Testing with Cucumber, Java and JUnit“.
It is also possible to integrate Cucumber in a complex Java EE project with Arquillian and the Cukespace extension – please feel free to have a look at another article of mine: “Marrying Java EE and BDD with Cucumber, Arquillian and Cukespace“.
Resources
BDD Articles of mine
The following articles of mine are covering different aspects and frameworks for Behaviour Driven Development:
Article Updates
-
2014-12-28: Link to my article about the Cucumber framework added.
-
2015-01-07: Link to my article about Cucumber in a Java EE environment and the cukespace extension added.
-
2017-04-06: Links to other BDD articles of mine added.