Access JBehave Examples table data in step

Olivia picture Olivia · Oct 9, 2013 · Viewed 8.5k times · Source

I would like to know if there is a way I can access examples table row data within a step method without passing it in as an argument?

Story file:

Given I am logged in
When I create a trade
Then a trade should be created

Examples:
|data1|data2|
|11111|22222|
|33333|44444|

Step file:

@When("I create a trade")
public void createTrade(@Named("data1") String data1, @Named("data2") String data2){
    //code to create trade using data1 and data2
}

Above works fine, but I would like a way to access the data row from the examples table within the method. (The reason I would like to do this is because all columns may not be present in the examples table in every story, and I have found that if I have say 3 * @Named as parameters in the step method, but one of these are missing from the actual examples table then it fails to run.)

@When("I create a trade")
public void createTrade(){
    //check if there is a data1 column, if so get value and do something
    //check if there is a data2 column, if so get value and do something
}

Thanks for your help

Answer

Tidhar Klein Orbach picture Tidhar Klein Orbach · Oct 15, 2013

You can implement a new parameter converter, and then pass the table as an object. for example, in our project we built ExamplesTableConverter (note: there is an our of the box JBehave converter that we didn't test):

public class ExamplesTableConverter extends ParameterConverters.ExamplesTableConverter {
private final ExamplesTableFactory factory;
private static final String ROW_SEPARATOR = "\n";
private static final String FIELD_SEPARATOR = "|";

public ExamplesTableConverter(){
    this(new ExamplesTableFactory());
}

public ExamplesTableConverter(ExamplesTableFactory factory){
    this.factory = factory;
}

@Override
public boolean accept(Type type) {
    if (type instanceof Class<?>){
        return ExamplesTable.class.isAssignableFrom((Class<?>) type);
    }
    return false;  //To change body of implemented methods use File | Settings | File Templates.
}

@Override
public Object convertValue(String tableAsString, Type type) {
    System.out.println(tableAsString);
    String[] rows = tableAsString.split(ROW_SEPARATOR);
    StringBuffer resultString = new StringBuffer();
    resultString.append(rows[0]);
    resultString.append(ROW_SEPARATOR);

    for(int i=1; i<rows.length; i++){
        String originRow = rows[i];
        List<String> rowValues = TableUtils.parseRow(originRow, FIELD_SEPARATOR, true);

        String translatedRow = translateRow(rowValues);
        resultString.append(translatedRow);
        resultString.append(ROW_SEPARATOR);
    }
    System.out.println(resultString.toString());
    Object table = factory.createExamplesTable(resultString.toString());
    return table;
    //return null; 
}

private String translateRow(List<String> rowValues) {
    StringBuffer result = new StringBuffer(FIELD_SEPARATOR);

    for(String field : rowValues){
        try{
        result.append(translate(field));
        result.append(FIELD_SEPARATOR);}
        catch (LocalizationException e){
            e.printStackTrace();
            //Need do something here to handle exception
        }
    }
    return result.toString(); 
}

}

then you need to add that converter to your configuration:

configuration.parameterConverters().addConverters(new ExamplesTableConverter());

create a method that use it

@When("create parameters of type $param1 from the next table: $table")    
public void doThis(@Named("param1") String param1, @Named("table") ExamplesTable table)

and last, use it in a story:

When create parameters of type type1 from the next table:
|FirstName|LastName|
|Donald|Duck|

this would allow you to iterate the table.

following blog post can also help you Simpler JBehave Examples Table Processing