From
JBehave site:
JBehave is a framework for
Behaviour-Driven Development (BDD).
JBehave allows developers, QA and non-technical or business participants, to write stories in a plain text file with minimal restrictions about grammar. Then a
POJO is created for executing created story. This
POJO should have the typical
BDD structure
Given, When and Then.
From
Springsource site:
Spring Framework is a
Java platform that provides comprehensive infrastructure support for developing
Java applications.
Spring handles the infrastructure so you can focus on your application.
From
Selenium site:
Selenium is a suite of tools to automate web app testing across many platforms.
We have three technologies
JBehave for
acceptance tests,
Selenium for
web application testing and
Spring dealing with
infrastructure. In this post I will talk about integrating
JBehave with
Selenium 2 and
Spring.
For this example I have created a very simple web application using
Spring MVC. I know that business logic is not accurate to the reality, but it is simple enough to illustrate how to integrate all these technologies together.
I have divided this post in three main subsections:
- Integrating JBehave with Spring. There is no web application here, only business logic.
- Integrating Spring MVC with Selenium 2. Only to show how easy is implementing automated tests with Selenium 2.
- Integrating JBehave with Selenium 2. Web application used in previous example but instead of using only Selenium for automating testing, JBehave instructs to Selenium which steps should execute.
Application that I will use is a simple
TraderService, (explained in
JBehave page (
http://jbehave.org/reference/stable/)). This
TraderService generates
Stocks, and if a
Stock is traded below threshold, its alert status is
OFF and if it is traded above, alert status is
ON.
In this tutorial I assume that you have a basic idea of JBehave and Spring.
- Integrating JBehave with Spring:
In this case no web GUI is used, we are going to use JBehave for writing acceptance tests of business logic.
Basic classes are:
- TradingService, that defines a method for creating stocks. TradingServiceImpl is the implementation.
- Stock, that contains stock information and logic about its status.
- StockAlertStatus is Stock status Enum.
Acceptance test part:
First of all we should create a story. A story is where stakeholders, developers... should say what they want the application do, and which are the expected results for given parameters. In our case a story has been created for validating that alarm is OFF if trade value is under threshold, and ON otherwise.
The important parts of that file are: Scenario for describing what we are testing, all symbols between <> that are used as variables, and Examples that are values injected to previous "<>" variables. In this story file two examples are provided, so two executions will be produced, one for each row. As final note, Given, When, Then words should be placed at start and are reserved words, also more than one Given, When or Then could be used in each story.
Next step, create a class that transforms a story written in "natural language" to code. We could say that this class is equivalent of creating a junit class; In JBehave these classes are called Steps. Because we are integrating with Spring an annotation called Steps is created. This annotation extends from Component annotation so Spring component-scan can wire up step classes too.
And Steps annotation is used in TradingServiceSteps class.
In TradingServiceSteps is where all magic occurs. This class is responsible of transforming story file to an execution. Let's see:
@Steps because we want Spring creates automatically this bean. TradingService is the business logic we want to test, and is injected using Autowire annotation. And finally one method for each Given, When, Then. Explained quickly, when JBehave finds an @Given, it searches into loaded stories for a phrase starting with Given. After that checks if @Given string value matches the Given definition expressed in story file. If matches then inject the story parameters as method parameters, for example STK1 as string parameter, or 5 as double threshold parameter. Moreover, in this case because we are using Examples in our story file, @Named annotation for each parameter is required. The named parameters allow the parameters to be injected using the table row values with the corresponding header name. Each parameter is converted from String to required parameter type.
We have written stories, and how to execute them (TradingServiceSteps class). JBehave requires another class, that will be responsible of configurating it. Basically you should configure Step classes and story files location, and what kind of reports are generated.
In our case, because we are integrating JBehave with Spring, some information is provided using Spring Injection.
This class is where JBehave is configured and is responsible for running all stories. Let's examine the most important lines:
In line 1 we specify a JUnit runner for running JBehave stories with Spring.
In line 2 we are configuring JBehave with Enum parameter converter, see that StockAlertStatus is an enum, because it is not a primitive parameter, a converter should be provided. JBehave comes with some convertes, but we can implement ours too.
In line 3 the embedder that we will use. This is the standard embedder for JBehave. Embedder represents an entry point to all of JBehave's functionality that is embeddable into other launchers.
And finally with @UsingSpring we are providing two Spring files, one where step classes are defined, and the other one where JBehave is configured.
Configuration file is a standard
Spring file injecting required
JBehave parameters:
This is a generic configuration file, that I use in all projects. You configure the output, the classloader for
Embedder and prefix for parameters
And finally a
Spring context file where all step classes are defined. And you know what, thanks of
Spring this is as simple as:
No magic, remember that each
Step class has an
@Steps annotation? Thanks of
component-scan, you don't have to define each
Step class in
@UsingSteps annotation or using
tags.
Now run previous class as
JUnit, and reports with results are generated.
- Integrating Spring MVC with Selenium 2
Selenium 2 is a suite of tools to automate web app testing across many platforms. In this case WebDriver approach has been used. WebDriver is an interface for automating tests in a programmatic way. Selenium provides several implementations depending on browser where tests are run.
For this example I have created an Spring MVC application, that are composed of two pages, one form where all stock information is provided and a page where status of inserted stock is showed. Of course Spring MVC controller for managing all information is also implemented.
Controller of this small application is:
showForm method is used for showing the form where user will write stock information. submitForm method is called when submit button is pushed, and creates an stock and send to showstatus page the status of stock.
StockForm is simply a class with three attributes (stock, threshold and tradeAt price). No secret here.
Form page is also so simply but I will show it because form information will be used for configuring Selenium:
WebDriver is used in JUnit test for automatizing a sequence of events. In this case, the sequence will create an stock below threshold and assert that response page shows that alert status is OFF.
Most important sections of previous JSP are:
JSP taglibs <form:input path=""/> like <form:input path="name"/> in form, and <div id="result">. These fields are important because they are used by Selenium for filling form and asserting showed status.
For example, in Selenium class:
WebElement name = driver.findElement(id("name")) returns a "reference" to <input id="name" type="text"> element and using sendKeys method, you are sending keyboard chars to that component.
WebElement element = driver.findElement(id("result")), returns a "reference" to div element and using
assertThat(element.getText(), is(StockAlertStatus.OFF.name())); getText method, none tag characters of element are returned.
Now running this test is as simple as running TraderIsAlertedSelenium class as a simple JUnit test class. When running this class a browser (Firefox in this case) will be opened, and all programmed interactions will be executed on your screen.
At this point we just have to join both previous parts, and integration between
JBehave with
Spring and
Selenium will be reality.
- Integrating JBehave with Selenium 2 and Spring
JBehave has a module called JBehave-Web, that is used for integrating JBehave with web pages. Base classes are WebDriverProvider and WebDriverPage. Both classes are used by JBehave for abstracting from browser, and also for providing common methods to test webpages. In this example I won't use jbehave-web for two reasons, first because Selenium 2 with WebDriver offers a level of abstraction that is enough for this example, and secondly because WebDriverPage is a class that implements some common funcionalities for testing, but it is abstract, I don't like using extension only for sharing common operations between classes, it is a bad practice (not discussed here), I prefer aggregation. So in this case I have preferred implementing my class for implementing common functionalities.
In this case abstraction from browser is acquired using WebDriver (Selenium) interface. Moreover all common operations are implemented into this class. The idea of this class is to be used in several projects and for that reason a better design should be desired, but for current example is enough.
Next group of classes are those that use PageUtils object. I have created one class for each page that Selenium should interact with. Acts as a facade to web.
For example class for dealing with page containing form to insert new stock is:
Three operations can be executed in this page, the first one is open the page. Because "insert a new stock" is accessed manually (in this case is the front page), an open method is provided with URL. Also a method for filling stock form and and another for submitting it are provided.
And finally a class that transforms an story written in "natural language" to code (also known as Steps class), this class would be the same used in first example (TradingServiceSteps) but adapted for dealing with web pages (using previous classes).
See that there is no differences between this class and the one created in first example, but using web page interfaces instead of business objects.
Next modified files are:
Story file:
that has been modified to use web terminology.
Spring file:
that injects into TradingServiceWebSteps required beans.
Configuration file used in first example is the same, and Spring file for configuring JBehave is the same too.
In summary I can definitely say that integrating
JBehave with
Selenium 2 and
Spring is not a difficult task, compared with the benefits that lead us having an
automated acceptance test platform. I wish you have found this post useful.
Download Full Code