Monday, March 12, 2012

Parsing JBehave tables

This is a simple sample how to parse JBehave tables.

In our project we often have to parse JBehave tables that might look like this one:

Given currencies are truncated to these decimal places
| Currency | Decimal places |
| USD | 2 |
| JPY | 0 |
| LYD | 3 |

The standard approach is to write something like this

@Given("currencies are truncated to these decimal places $currencyDecimalPlaces")
public void currencyDecimalPlaces(ExamplesTable currencyDecimalPlacesTable) {
...
for (Parameters row : currencyDecimalPlacesTable.getRowsAsParameters()) {
// read row data
}
...
}

where reading row data may look like this:

CurrencyCode currencyCode = row.valueAs("Currency", CurrencyCode.class);
Integer decimalPlaces = row.valueAs("Decimal places", Integer.class);

or we can make it a little more readable like this:

CurrencyCode currencyCode = Currency.in(row);
Integer decimalPlaces = DecimalPlaces.in(row);

To make the readable code we define a new Column class:

public class Column<T> {

private final String label;
private final Class<T> defaultType;


public Column(String label, Class<T> defaultType) {
this.label = label;
this.defaultType = defaultType;
}


public <T> T in(Parameters row, Class<T> type) {
return row.valueAs(label, type);
}


public T in(Parameters row) {
return in(row, defaultType);
}


public String asString(Parameters row) {
return in(row, String.class);
}


public static <T> Column<T> column(String label, Class<T> defaultType) {
return new Column<T>(label, defaultType);
}


public static Column<String> column(String label) {
return new Column<String>(label, String.class);
}
}

and registering custom columns:

public interface Columns {

...

public static final Column<CurrencyCode> Currency = column("Currency", CurrencyCode.class);
public static final Column<Integer> DecimalPlaces = column("Decimal places", Integer.class);

...
}

now we can convert the column to the default registered class

CurrencyCode currencyCode = Currency.in(row);

or to a specified class:

String currencyCode = Currency.in(row, String.class);