Cucumber not serializing date string from datatabl

2020-07-27 20:35发布

问题:

Im trying to figure out how to parse date fields from my cucumber feature files in my step definitions.

class Person{ 
  String name
  LocalDate dob
}

scenario: do something with people
Given  list of people:
                     |name|dob|
                     | john| 20-09-2001|

@Given("^list of people:")
public void doSomething(List<Person> people) {

}

Please note i have no access to the Person class, Im sure i have to either write my own converter or register a converter written by someone from some library, after searching around the only options i can see are to change them pojo with a @Transform on the java.time.LocalDate field.

I'm currently getting the following exception

cucumber.runtime.CucumberException:              cucumber.deps.com.thoughtworks.xstream.converters.ConversionException: Cannot deserialize object with new readObject()/writeObject() methods
---- Debugging information ----
class               : java.time.LocalDate
required-type       : java.time.LocalDate
converter-type      : cucumber.deps.com.thoughtworks.xstream.converters.reflection.SerializableConverter
path                : /list/com.pkg.Person/dob

I have tried changing the dateformat to yyyy-MM-dd, that usually works but not on this occasion. I would be gratefull for any pointers on how to setup and register a custom converter

my cucumber dependencies are as follows, i can chane these if required to newer versions if it makes any difference.

    <dependency>
        <groupId>io.cucumber</groupId>
        <artifactId>cucumber-java</artifactId>
        <version>2.4.0</version>
    </dependency>

    <dependency>
        <groupId>io.cucumber</groupId>
        <artifactId>cucumber-junit</artifactId>
        <version>2.4.0</version>
        <scope>test</scope>
    </dependency>

    <dependency>
        <groupId>io.cucumber</groupId>
        <artifactId>cucumber-spring</artifactId>
        <version>2.4.0</version>
    </dependency>

回答1:

Cucumber does not support automatic conversion of the new java date time classes. But it does support conversion to the old util Date class which is of no use as you do not have write access to the dataobject.

For this to work you will need to use the @XStreamConverters annotation on the test runner. This will add the custom xstream converter to the out of the box converters in cucumber.

@RunWith(Cucumber.class)
@CucumberOptions(plugin = { ""}, tags = { "" }, glue = "stepdefs",
        features = "" ) --> use your own values
@XStreamConverters(@XStreamConverter(LocalDateCon.class))
public class RunSampleTest {

Now the converter class to parse the string into LocalDate and create the collection of dataobjects. This will support dates like "15-05-2016". Just change the DEFAULT_DATE_PATTERN according to your date format.

public class LocalDateCon implements Converter{

    public boolean canConvert(Class type) {
        //return type.equals(LocalDate.class);
        return LocalDate.class.isAssignableFrom(type);
    }

    private static final String            DEFAULT_DATE_PATTERN = "dd-MM-yyyy";
    private static final DateTimeFormatter DEFAULT_DATE_FORMATTER = DateTimeFormatter.ofPattern(DEFAULT_DATE_PATTERN);

    public void marshal(Object value, HierarchicalStreamWriter writer, MarshallingContext context) {
        LocalDate  date = (LocalDate) value;
        String result = date.format(DEFAULT_DATE_FORMATTER);
        writer.setValue(result);
    }

    public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {
        LocalDate result = LocalDate.parse(reader.getValue(), DEFAULT_DATE_FORMATTER);
        return result;
    }

}

Also you will not be able to use @Transform annotation cleanly as it works only for a single value and not a collection. I used cleanly as one will need to do the object creation in the converter code which is messy.