Reputation: 316
I am using Cucumber Data Tables. I want to convert this Data Table into a Map rather than a list. So basically what if I use the Header Row as Key and the data rows as value for the key. How should I do that?
Let me share 1 example to be more clear.
Given the following animals:
| Type | BabyAnimal |
| cow | Calf |
| horse | Pony |
| sheep | Lamb |
Instead of creating a List<List<String>>
here, it is a better approach to use a List<Map<String,String>>
here.
Map's Key should contain 'Type' and 'BabyAnimal' and values should contain the respective values.
So the Map entities would be:
<Type,cow>,<BabyAnimal,Calf>
<Type,horse>,<BabyAnimal,Pony>
<Type,sheep>,<BabyAnimal,Lamb>
How would we do that?
I feel this is a better approach of doing because we are fetching the data from the keys.
eg List(1).Map.get(Type)
Whereas in case of List we would have to do a get(0), get(1) and there are chances of using incorrect data.
Upvotes: 7
Views: 31390
Reputation: 15879
Perhaps the API has moved on since this question was first posted. I'm using cucumber version 4.8.1 and this code gives what you need without the cumbersome Lists of Maps
Map<String, String> map = dataTable.asMap(String.class, String.class);
Upvotes: 3
Reputation: 81
In Cucumber 3.0.2, just call asMaps() from DataTable.
public void feature_step(DataTable dataTable) {
List<Map<String, String>> data = dataTable.asMaps();
String type = data.get(0).get("Type");
Strig babyAnimal = data.get(0).get("BabyAnimal");
}
Upvotes: 2
Reputation: 12029
And adding a second answer because the generic types in your question got munched by the html.
Given the following animals:
| Type | BabyAnimal |
| cow | Calf |
| horse | Pony |
| sheep | Lamb |
And assuming you want this to be your step definition:
@Given("all baby animal details")
public void allMapDetails(List<Map<String, String>> animals) {
System.out.println(animals);
}
Then the table will be automatically converted to a list of maps of string to string.
Upvotes: 5
Reputation: 12029
Given the following animals:
| Type | BabyAnimal |
| cow | Calf |
| horse | Pony |
| sheep | Lamb |
And assuming you want this to be your step definition:
@Given("all baby animal details")
public void allMapDetails(Map<Type,BabyAnimal> animals) {
System.out.println(animals);
}
When you define these paramter types:
public class ParameterTypes implements TypeRegistryConfigurer {
@Override
public Locale locale() {
return ENGLISH;
}
@Override
public void configureTypeRegistry(TypeRegistry typeRegistry) {
typeRegistry.defineDataTableType(new DataTableType(
Type.class,
(Map<String, String> row) -> new Type(row.get("Type"))
));
typeRegistry.defineDataTableType(new DataTableType(
BabyAnimal.class,
(Map<String, String> row) -> new BabyAnimal(row.get("BabyAnimal"))
));
}
}
Then the table will be converted to a map of animal type to baby animal.
Upvotes: 1
Reputation: 9058
As mentioned in Marit's answer, if you are on v3 plus you will need to work a bit more. Instead of a getting back a List of Maps, you can get back a custom object which contains the List of Maps.
Refer to this to figure out about a configuration class to mention all the datatable conversions - Cucumber-JVM - io.cucumber.datatable.UndefinedDataTableTypeException
Place this bit of code into this class.
registry.defineDataTableType(new DataTableType(Animals.class, new TableTransformer<Animals>() {
@Override
public Animals transform(DataTable table) throws Throwable {
Animals animals = new Animals();
table.asMaps().forEach(e -> animals.addAnimal(e));
return animals;
}
}));
This is the container or dataobject class.
public class Animals {
public static final String type = "type";
public static final String baby = "babyanimal";
private List<Map<String, String>> details = new ArrayList<>();
public void addAnimal(Map<String, String> entry) {
details.add(entry);
}
public List<Map<String, String>> getDetails() {
return details;
}
@Override
public String toString() {
return "Animals [details=" + details + "]";
}
}
Step definition
@Given("all baby animal details")
public void allMapDetails(Animals anim) {
System.out.println(anim.getDetails());
}
You should get something like this -
[{type=horse, babyanimal=Pony}, {type=sheep, babyanimal=Lamb}, {type=cow, babyanimal=Calf}]
Upvotes: 2
Reputation: 3026
You can find the following DataTable hint in the cucumber-jvm project on GitHub:
" // For automatic transformation, change DataTable to one of\n" +
" // E, List<E>, List<List<E>>, List<Map<K,V>>, Map<K,V> or\n" +
" // Map<K, List<V>>. E,K,V must be a String, Integer, Float,\n" +
" // Double, Byte, Short, Long, BigInteger or BigDecimal.\n" +
" //\n" +
" // For other transformations you can register a DataTableType.\n";
You can find how, in the Cucumber documentation:
The simplest way to pass a List to a step definition is to use a data table:
Given the following animals:
| cow |
| horse |
| sheep |
Declare the argument as a List, but don’t define any capture groups in the expression:
@Given("the following animals:")
public void the_following_animals(List<String> animals) {
}
In your case, replace List
with Map
.
Upvotes: 1