Woland Woland - 1 month ago 14
Java Question

org.springframework.web.client.HttpClientErrorException: 400 null

I wrote test for

FilterDataController
. But I have the following error during execution test. When I send manually GET request I receive correct JSON.

org.springframework.web.client.HttpClientErrorException: 400 null

at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:91)
at org.springframework.web.client.RestTemplate.handleResponse(RestTemplate.java:667)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:620)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:580)
at org.springframework.web.client.RestTemplate.getForEntity(RestTemplate.java:312)
at com.instinctools.mailtracker.integration.tests.rest.StatisticEndpointTest.checkFilterDataControllerInvalidBodyResponse(StatisticEndpointTest.java:284)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:252)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:94)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:191)
at org.junit.runners.Suite.runChild(Suite.java:128)
at org.junit.runners.Suite.runChild(Suite.java:27)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:117)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:42)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:262)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:84)


My test:

@Test
public void checkFilterDataControllerInvalidBodyResponse() {
String servicePath = getBaseUrl() + "/statistics/filters?startDate={startDate}&endDate={endDate}";
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<String> response = restTemplate.getForEntity(servicePath, String.class, "", "");
assertThat(response, notNullValue());
assertThat(response.getStatusCode(), equalTo(HttpStatus.BAD_REQUEST));
}


FilterDataController


/**
* controller which provides possible filters data for UI
*/

@RestController
@RequestMapping("/statistics")
@Api(value = "/statistics",description = "API for possible filters data")
public class FilterDataController {

public static final String DATE_FORMAT = "yyyy-MM-dd";

@Autowired
private FilterDataProvider filterDataProvider;

@ApiOperation(value = "Get possible filter data",response = ResponseEntity.class)
@ApiResponses(value = {
@ApiResponse(code = 200, message = "The response data should be used as bricks in all future statistics requests"),
@ApiResponse(code = 204, message = "Data not found. Select another timeframe")})
@RequestMapping(path = "/filters", method = RequestMethod.GET)
public ResponseEntity<Object> getPossibleFilterData(
@RequestParam(value = "startDate") @DateTimeFormat(pattern=DATE_FORMAT) final Date startDate,
@RequestParam(value = "endDate") @DateTimeFormat(pattern=DATE_FORMAT) final Date endDate) {
if (startDate == null || endDate == null){
throw new ValueNotAllowedException("Dates mustn't be null");
}
if (endDate.compareTo(startDate) == -1){
throw new ValueNotAllowedException("End date should be after or equal start date");
}
else {
Date newEndDate = endDate;
if (startDate.equals(endDate)){
newEndDate = new Date(endDate.getTime() + TimeUnit.DAYS.toMillis(1) - 1);
}
List<String> possibleMails = Lists.newArrayList(filterDataProvider.getPossibleMails(startDate, newEndDate));

<...>

return new ResponseEntity<>(new FilterResponse(possibleMails, possibleSubjects, possibleCountries, possibleSizes, possibleStates),HttpStatus.OK);
}
}

@ExceptionHandler(ValueNotAllowedException.class)
void handleBadRequests(HttpServletResponse response, ValueNotAllowedException ex) throws IOException {
response.sendError(HttpStatus.BAD_REQUEST.value(), ex.getMessage());
}
}


Response from Postman:

GET http://localhost:8888/statistics/filters?startDate=&endDate=

{
"timestamp": 1476690591750,
"status": 400,
"error": "Bad Request",
"exception": "com.services.exceptions.ValueNotAllowedException",
"message": "Dates mustn't be null",
"path": "/statistics/filters"
}


Params that I send to
getForEntity
is correct, because when I send the same params but with correct dates - it's works good.

Answer

You should use TestRestTemplate instead of RestTemplate.

Class TestRestTemplate

Convenient alternative of RestTemplate that is suitable for integration tests. They are fault tolerant, and optionally can carry Basic authentication headers. If Apache Http Client 4.3.2 or better is available (recommended) it will be used as the client, and by default configured to ignore cookies and redirects.

Change

@Test
public void checkFilterDataControllerInvalidBodyResponse() {
    String servicePath = getBaseUrl() + "/statistics/filters?startDate={startDate}&endDate={endDate}";
    RestTemplate restTemplate = new RestTemplate();
    ResponseEntity<String> response = restTemplate.getForEntity(servicePath, String.class, "", "");
    assertThat(response, notNullValue());
    assertThat(response.getStatusCode(), equalTo(HttpStatus.BAD_REQUEST));
}

To

@Test
public void checkFilterDataControllerInvalidBodyResponse() {
    String servicePath = getBaseUrl() + "/statistics/filters?startDate={startDate}&endDate={endDate}";
    TestRestTemplate restTemplate = new RestTemplate();
    ResponseEntity<String> response = restTemplate.getForEntity(servicePath, String.class, "", "");
    assertThat(response, notNullValue());
    assertThat(response.getStatusCode(), equalTo(HttpStatus.BAD_REQUEST));
}