Intelligent Data Types - JBehave Examples

Posted by Ritinder Kaur

JBehave is a flexible and extensible framework for Behavior-Driven Development (BDD). It provides an easy way to create Intelligent Data Types for software quality assurance so that these can be passed as actionable parameters in the code.

JBehave examples

Some of the possible scenarios in which we can leverage this feature to facilitate data interpretation are as follows:

  • To create a Facebook test account, we can pass a test email id through the <Facebook> parameter.
  • We can pass an email id through the parameter <emailid>, strip off the domain and create an email in yopmail.
  • We can process data that has multiple data types like strings, dates or numeric values for each parameter, such as in vendor quotations.
  • We can read JSON/XML from an REST API and create a corresponding object hierarchy.

For the purpose of this article, let us take the data type scenario and show how we can set up the code for a custom data type. Let’s look at a story for selecting the lowest priced quote from among multiple files in a folder and placing an order.

1
2
3
4
5
6
7
8
Scenario: Select and purchase least pricey quote
Given that user has quotations in the folder <quotation>
When user selects least cost quote
Then this least cost quote should come by default when creating a purchase order.
Examples
|quotation|
|/WasherQuote/|
|/PaintQuote/|
   

 

Table 1 - The story

Since the purpose of this article is to discuss intelligent data types in JBehave, we will focus only on how to read the quotations from the folder into a list using our custom data type, that is, just the Given statement.

1
2
3
4
5
6
@Given("that user has quotations in the folder <quotation>")
public void readQuotation(@Named("quotation") Quotations quotationMap)
{
quotationMap.quotes(1).VendorName
// opens weburl
}
   

 

Table 2 - The code behind

JBehave will look for matching strings after the statements in the story and the code. When it finds an exact match - the Given statements in both - it can map the JAVA code-behind method to the step and execute it. The variable <quotation> should be the same in the story and the code-behind so that the value can be passed from the story file to the JAVA code.

Startup and registering QuotationsConverter with JBehave

At startup, JBehave calls the overridden configuration() method (Table 3 below).

 1
2
3
4
5
6
7
8
9
10
11
12
13
@Override
public Configuration configuration() {
Configuration configuration = new MostUsefulConfiguration()
.useParameterConverters(
new ParameterConverters().addConverters(customConverters()));
return configuration;
}

private ParameterConverter[] customConverters() {
List<ParameterConverter> converters = new ArrayList<ParameterConverter>();
converters.add(new QuotationsConverter ()); // custom number format
return converters.toArray(new ParameterConverter[converters.size()]);
}

 

Table 3 - Registering the parameter converter

In the configuration() method, we set up the array of parameter converters (line 6). The method customConverters() is a helper that returns an array of parameter converters and QuotationsConverter is one of the converters that it returns in the array.

We need to create an object of Quotations data type in which we will store the quotations that are read from the folder. To do this, we need to write a parameter converter - QuotationsConverter.

Why would we use a List within the method customConverter() when it returns an array? Well, a List is easier to manipulate than arrays. Moving up this table, the addConverters() method (line 5) will register this array of parameter converters, including QuotationsConverter, with JBehave.

New call-to-action

Declare QuotationsConverter class

Next, we declare QuotationsConverter class (Table 4), implementing the methods of interface ParameterConverter - accept() and convertValue().

The accept() method returns true when the type passed is Quotations; it indicates to JBehave that QuotationsConverter wants to process the value. Next, JBehave calls convertValue(), passing it the value it got from the Examples table in the story (Table 1) and the type it needs to be interpreted to, in our case, Quotations.
The convertValue() method will read the quotations folder and parse the quotations in it into a List. This list is then attached to the Quotations object, which will then be returned. The code in Table 4 shows how this method works.

This returned Quotations object will then be passed to the variable quotationMap (Table 2). Now, within Given in the code-behind, we have a Quotations object having data of all quotations; this can be used to weave our logic.  

 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class QuotationsConverter implements ParameterConverter {

public boolean accept(Type type) {
if (type instanceof Class<?>) {
return Quotations.class.isAssignableFrom((Class<?>) type);
}
return false;
}

public Object convertValue(String value, Type type) {
Quotations Quotations = new Quotations();
// Read the folder in value and fill the quotation from file to a List.
Quotations.addQuotes(//List from above);
return Quotations;
}
}

 

Table 4 - Declare the parameter converter 

So, to create Intelligent Data Types in JBehave, you must:

     1.  Declare a parameter class.
     2.  Declare its corresponding parameter converter and register it with JBehave.
     3.  Update the code-behind to use this parameter for reading data.

Let’s go through the sequence of steps followed by JBehave :

  • When JBehave starts up, it calls the override configuration() method. All parameter converters, including our custom parameter converter, are registered with JBehave.
  • It looks up the stories and for each scenario in the story, reads the steps and then starts executing them in turn.
  • It maps the step in the feature/story file to a step in the code-behind by matching the text of the step to that with the meta tags in the code-behind file.
  • JBehave then reads the values of all the parameters in the step to memory.
  • It starts executing the steps in the code-behind method.
  • On encountering @Named, it reads the value of the variable mentioned within quotes from memory.
  • It reads the value as a string (JBehave always does) and checks the data type expected for the parameter.
  • To confirm if the parameter converter for said data type is registered, it sends the string to the accept() method of the parameter converters registered with it.
  • If the accept() method of a parameter converter returns true, JBehave calls the convertValue() method with the string value and the data type, which it is expected to return. Thus, convertValue() returns an instance of the object.
  • The returned object is then assigned to the variable in the Given step in the code-behind file. This parameter is used to read data that is passed to the code.

New call-to-action