Reputation: 1621
I have get mapping like this:
@GetMapping(value = "/topics", params = "dateRange")
public Set<Integer> getTopicsInRange(@RequestParam DateRange dateRange) {
return topicService.getTopicsInRange(dateRange);
}
And now I would've like to test it as:
private final static DateRange VALID_DATE_RANGE = new DateRange(LocalDate.of(2018, 1, 1), LocalDate.of(2018, 2, 2));
@Test
public void gettingTopicsInRangeShouldReturn200(){
given().
.when()
.get(String.format("/topics?dateRange=%s", VALID_DATE_RANGE)
.then()
.statusCode(200);
}
Expected status code <200> doesn't match actual status code <400>.
I know that my solution would've work if I would've change my DateRange param into 2 separated params as:
@GetMapping(value = "/topics", params = {"begin", "end"})
public Set<Integer> getTopicsInRange(@RequestParam Date begin, @RequestParam Date end) {
return topicService.getTopicsInRange(begin, end);
}
and then test it as /topics?begin=value&end=value2
but it's not what I'm looking for (in case of DateRange would've like 10 fields making 10 params would've be really excessive I think)
Any ideas how can I solve my problem?
EDIT This is my DateRange class:
@Data
@AllArgsConstructor
@NoArgsConstructor
public class DateRange {
LocalDate begin;
LocalDate end;
}
Upvotes: 1
Views: 8121
Reputation: 3961
Add DateTimeFormat
annotation:
public class DateRange {
@DateTimeFormat(pattern = "yyyy-MM-dd")
private LocalDate begin;
@DateTimeFormat(pattern = "yyyy-MM-dd")
private LocalDate end;
// getter and setters
}
Receive object in controller:
@GetMapping(value = "/topics")
public Set<Integer> getTopicsInRange(DateRange dateRange) {
return topicService.getTopicsInRange(dateRange);
}
And send params separately:
@Test
public void gettingTopicsInRangeShouldReturn200() {
given()
.queryParams("begin", LocalDate.of(2018, 1, 1).format(ISO_DATE),
"end", LocalDate.of(2018, 2, 2))
.when()
.get("/topics")
.then()
.statusCode(200);
}
Upvotes: 2
Reputation: 7531
You need a way to convert your DateRange class to String and vice versa. Since you are using Spring, this could be done like this:
1) Add conversion logic
@Data
@AllArgsConstructor
@NoArgsConstructor
public class DateRange {
LocalDate begin;
LocalDate end;
private static final String DELIMITER = "_";
public static DateRange fromFormattedString(String source) {
if (source != null) {
String[] tokens = source.split(DELIMITER);
if (tokens.length == 2) {
return new DateRange(
LocalDate.parse(tokens[0]), // begin
LocalDate.parse(tokens[1]) // end
);
}
}
return null;
}
public String toFormattedString() {
return begin + DELIMITER + end;
}
}
2) Create Spring converter
import org.springframework.core.convert.converter.Converter;
public class DateRangeConverter implements Converter<String, DateRange> {
@Override
public DateRange convert(String source) {
return DateRange.fromFormattedString(source);
}
}
3) Register this converter
This will allow Spring to handle DateRange objects passed as @RequestParam
-s
@Configuration
public class WebApiConfiguration extends WebMvcConfigurationSupport {
...
@Override
public FormattingConversionService mvcConversionService() {
FormattingConversionService f = super.mvcConversionService();
f.addConverter(new DateRangeConverter());
return f;
}
...
}
And finally use like:
.get(String.format("/topics?dateRange=%s", VALID_DATE_RANGE.toFormattedString())
or (with raw string):
.get(String.format("/topics?dateRange=%s", "2018-1-1_2018-2-2")
BUT:
Nonetheless, I'd recommend you to use separate request params (begin, end, etc) even if there are 10 of them because it's:
1) RESTful way
2) error-proof, since the order request params are passed in, is not strict. On the other hand, packing params into single object will force you to keep an eye on params order. Moreover you must pack all params in string, so no optional params are allowed, otherwise unpacking logic could be broken
Upvotes: 0