Following Part I of this series we now discuss the Java implementation.
Writing Stories and Java Implementation
The following is a discussion of some Volcano test cases and their Java implementation.
Let’s zoom in on the first story, which is the Volcano registration story file:
As a volcano enthusiast, Dani would like to register to Volcano Social Network.
A new user is signs-up for the volcano system.
Given Dani Shemesh is a Volcano enthusiast
When Dani signs-up for Volcano with the user name: dani and the password: 123456
Then Dani is able to log-in with the user name: dani and the password: 123456
The ‘Given’ is linked with a Java method. The method should:
- Carry the Jbehave @Given annotation
- The String parameter of the annotation should match the text described in the step, while the user name (i.e.) ‘dani shemesh’ is replaced with a variable $user
- To capture the user parameter, the function receives a String parameter, following the @Named annotation
The @Given implementation of this scenario is a dummy for obvious reasons.
Next is the implementation of the registration step where we cache the user details:
And the verification step, where the user should be able to log in and have a live token.
Note that we have used a cache to store the new user’s details in the registration step.
Considering other future user actions, such as “change password” and “add a friend”, the user is required to be logged-in, meaning that this would be a given step:
Given dani is logged-in…
Now, we want to:
- Re-use the java implementation of the log-in method (reuse @Given methods)
- Avoid creating a new user and log-in before each scenario (reuse @When actions)
This brings up unexpected challenges from an OOP point of view. Before discussing them, let’s explain why
The Jbehave environment
Though we are writing in Java, we are not in an OOP scope, but in Jbehave’s scope.
When JBehave begins, it registers all the implemented methods and their parameters. It then reads the steps in each scenario for each story and maps them to the appropriate method in the code behind. Here, all their values are in the memory and are executed one by one. The memory is cleaned after each story.
Re-use the @Given methods
This one is easy. Instead of inheritance/composition, we can place the @Given methods wherever we like, and Jbehave will identify it. So, we’ll create a dedicated class for given methods, dealing with user scenarios:
Implement tests for similar entities in the same class
We can once again take advantage of the Jbehave environment to place test implementations with similar characters together, even if they implement steps of different stories, for example:
Re-use actions with Dependency Injection using Spring
To reuse actions, in our case the user that we created and logged in with in the “registration” step, needs to be cached. We cannot put the cache in a global variable or static at some place, since we are working with different classes and the memory cleans up after each story.
Luckily, Jbehave supports some of the most popular, Java-based, dependency injection plugins. The most popular is probably Spring, and we’ll use it to inject the resources (i.e. the cache) we need for reusing actions.
We’ll use ‘org.springframework’ artifacts for the Spring integration:
To make our test classes to be singleton spring beans, using the @Service annotation:
to identify the test classes beans under com.fullgc.jbehave namespace, using @ContextConfiguration annotation and a spring-context xml file:
To inject the resources to the test classes, using the @Autowired annotation and the following Thucydides artifact
For the integration of the bean classes and with Jbehave, using SpringIntegration class.
The UserAccount test class now looks like this:
Note that the new user is cached and reused for a “change password” action.
(We use the cache in the same fashion as the ‘add friend’ story, which we won’t cover here, but can be found in the ‘Volcano’ repository)
The other test classes should be modified in a similar fashion.
The spring context:
In Part III we’ll learn how to launch the web app in compile time, run the tests and generate summary reports.