我正在为Spring-Boot应用程序编写组件测试,以测试我的安全配置。因此,我正在运行测试,该测试应该测试成功的响应以及“禁止”状态。 我遇到的问题是,因为我的REST调用期望使用复杂的JSON,对于阻塞的调用,测试失败,因为TestRestTemplate试图反序列化不存在的响应正文。
我正在运行一个Spring-Boot应用程序,并且测试类带有以下注释:
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
我正在尝试测试应该返回用户列表的REST API。 通话的简化版本为:
ResponseEntity<List<User>> responseEntity = testRestTemplate.exchange(URL, HttpMethod.GET, entity, new ParameterizedTypeReference<List<User>>() {});
其中TestRestTemplate由Spring自动装配,并且实体包含授权信息。
对于未经授权的请求,我收到如下错误:
org.springframework.web.client.RestClientException: Error while extracting response for type [java.util.List<my.package.User>] and content type [application/json;charset=UTF-8]; nested exception is org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot deserialize instance of `java.util.ArrayList` out of START_OBJECT token; nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of `java.util.ArrayList` out of START_OBJECT token
at [Source: (PushbackInputStream); line: 1, column: 1]
如果我将响应实体更改为接收String而不是List,则我将接收到响应,并且可以检查状态并确认它是“禁止的”
ResponseEntity<String> responseEntity = testRestTemplate.exchange(URL, HttpMethod.GET, null, String.class);
我知道我可以通过以下方法解决此问题:
但是由于TestRestTemplate应该是一个容错的便利子类,所以我希望它是开箱即用的,而不是尝试对错误响应进行反序列化。
我在这里错过了什么吗?我用错了吗?
答案 0 :(得分:0)
也许我不理解问题,但是为什么您没有通过使用RestClientException类捕获异常。如果不是这种情况,那么您需要尝试上述解决方法。
答案 1 :(得分:0)
我希望实现ResponseErrorHandler
可以帮助您解决此问题。
但是对于 RestTemplate ,这是向不成功的结果抛出错误的默认行为,您确定尚未覆盖它吗?也许您可以使用专用的RestTemplate
进行测试。
接收到HTTP 4xx时引发的异常。
有关实现ResponseErrorHandler
的信息,请参见https://www.baeldung.com/spring-rest-template-error-handling
编辑:实际上,对于 TestRestTemplate ,这不是默认行为,它意味着具有以下优点的集成测试:
模板通过不对服务器端错误引发异常来以一种易于测试的方式运行
...
- 不遵循重定向(因此您可以声明响应位置)。
- 将忽略Cookie(因此模板是无状态的)。
就您而言,您在测试代码中保证会返回用户列表,但事实并非如此,我不希望代码对此具有弹性,我什至会说{{1} }可能更有意义。
答案 2 :(得分:0)
很抱歉再次提出这个将近 2 年前的问题,但我在使用 Spring TestRestTemplate
和否定验证测试时遇到了一个非常相似的问题。
正如 Martin 在他的回答中提到的,TestRestTemplate
不包括通常与正确的 ResponseErrorHandler
相关联的 RestTemplate
。但响应正文仍将包含错误消息而不是 User
列表。
就我而言,我的网络应用程序有 @ControllerAdvice
,它包含所有常见的验证错误(MethodArgumentNotValidException
、MethodArgumentTypeMismatchException
等)并返回我自己的类 {{1 }}。控制器会将其编组为 JSON 而不是预期的响应。
我的组件测试最初试图捕获 ErrorMessageDto
,因为它是由普通的 HttpStatusCodeException
抛出的。在测试中,没有抛出异常(因为缺少 RestTemplate
),我的 ResponseErrorHandler
只是返回了一个空版本的 restTemplate.postForObject(path, request, MyResponse.class)
。
在阅读了 Martin 的描述和以下链接后,我将其更改为
MyResponse
就您而言,我确信您返回的错误消息是错误消息类的一个实例。您可能通过返回字符串并手动编组的建议意识到了这一点。如果您知道错误消息所代表的类,您可以简单地将其替换为 ResponseEntity<ErrorMessageDto> responseEntity = restTemplate.postForEntity(path, request, ErrorMessageDto.class);
// Do assertions on the response code and body (using assertj)
assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.UNPROCESSABLE_ENTITY);
assertThat(responseEntity.getBody().getErrors())
.extracting("path", "message")
.contains(tuple("firstName", "size must be between 0 and 255"))
中的类型。