春季引导 REST 控制器集成测试返回 406 而不是 500。

huangapple go评论85阅读模式
英文:

Spring Boot REST Controller Integration Test returns 406 instead of 500

问题

我有一个带有生成压缩数据字节流的端点的控制器。下面的代码中的 ``MyDTO``  ``ZipService`` 类是自定义类,它们作为一个普通的POJO,我想将它们的内容添加到压缩文件中,并且有一个服务会将POJO的字节写入 ``ZipOutputStream``,然后通过端点包装在带有适当的 ``HttpStatus`` 和标头的 ``ResponseEntity`` 对象中提供。 “正常情况” 运行良好,并且按预期生成 zip 文件。

```java
@GetMapping(path = "/{id}/export", produces = "application/zip")
public ResponseEntity<byte[]> export(@ApiParam(required = true) @PathVariable(value = "id") String id) throws IOException {
    try {
        MyDTO myDTO = myService.getDTO(id);
        byte[] zippedData = zipService.createZip(myDTO.getBytes());
        HttpHeaders httpHeaders = new HttpHeaders();
        httpHeaders.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"name.zip\"");
        return new ResponseEntity<>(zipDTO.getData(), httpHeaders, HttpStatus.OK);
    } catch (ZipException e) {
        return new ResponseEntity(e.getRestError(), HttpStatus.INTERNAL_SERVER_ERROR);
    }
}

问题出现在我的集成测试类中,当我想要测试自定义 ZipException 被抛出的情况时(如果压缩数据存在问题,可能会发生这种情况)。我们组织内必须遵守的一个标准是,每个自定义异常都需要扩展 Exception 并具有称为 RestError 的自定义对象,其中包含表示自定义错误代码和消息的字符串变量。

@JsonInclude(JsonInclude.Include.NON_EMPTY)
public class RestError {

	private String code;
	private String message;

    //构造函数
    
    //Getter和Setter
}

这个对象似乎会导致集成测试出现问题。

@Test
public void myIntegrationTest() throws Exception {
    MyDTO myDTO = new MyDTO();
    RestError restError = new RestError("Custom error code", "Custom error message");
    ZipException zipException = new ZipException(restError);
    given(myService.getDTO("id")).willReturn(myDTO);
    given(zipService.createZip(any(), any())).willThrow(zipException);

    mockMvc.perform(get("/{id}/export", "id").accept(MediaType.ALL)
            .andDo(print())
            .andExpect(status().is5xxServerError());
}

在这种情况下,我期望得到一个 HTTP 状态码为 500,但是 MockMvc 却得到了一个 406 - 内容不可接受的 HTTP 状态码。我已经尝试过让测试接受和期望任何/所有数据,但它仍然每次都返回 406 错误。我知道这与异常的 RestError 对象有关,因为如果我从控制器返回的 ResponseEntity 中去掉它,那么就会返回期望的响应状态。对此的任何帮助都将不胜感激。


<details>
<summary>英文:</summary>

I have a controller with an endpoint that produces a byte stream of zipped data.  The ``MyDtO`` and ``ZipService`` classes in the code below are custom classes that function as a POJO whose contents I want to add to the zip and a service that will take the bytes of the POJO and write them to a ``ZipOutputStream`` which will then be made available via the endpoint wrapped in a ``ResponseEntity`` object with the appropriate ``HttpStatus`` and headers.  The “happy path” is working fine and is producing the zip file as expected.

@GetMapping(path = "/{id}/export", produces = "application/zip")
public ResponseEntity<byte[]> export(@ApiParam(required = true) @PathVariable(value = "id") String id) throws IOException {
try {
MyDTO myDTO = myService.getDTO(id);
byte[] zippedData = zipService.createZip(myDTO.getBytes());
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=&quot;"name.zip&quot;");
return new ResponseEntity<>(zipDTO.getData(), httpHeaders, HttpStatus.OK);
} catch (ZipException e) {
return new ResponseEntity(e.getRestError(), HttpStatus.INTERNAL_SERVER_ERROR);
}
}


The problem is in my integration test class when I want to test the case where a custom ``ZipException`` is thrown (which could happen if there is a problem with the data being zipped).  One of the standards we have to adhere to in our organization is that each custom exception needs to extend ``Exception`` and have a custom object called RestError that has String variables that represent custom error codes and messages.  

@JsonInclude(JsonInclude.Include.NON_EMPTY)
public class RestError {

private String code;
private String message;

//Constructors

//Getters and setters

}


This object seems to cause a problem with the integration tests

@Test
public void myIntegrationTest() throws Exception {
MyDTO myDTO = new MyDTO();
RestError restError = new RestError("Custom error code", "Custom error message")
ZipException zipException = new ZipException(restError);
given(myService.getDTO("id")).willReturn(myDTO);
given(zipService.createZip(any(), any())).willThrow(zipException);

mockMvc.perform(get(&quot;/{id}/export&quot;, &quot;id&quot;).accept(MediaType.ALL)
        .andDo(print())
        .andExpect(status().is5xxServerError());

}


I would expect a ``HttpStatus`` of 500 in that case but the ``MockMvc`` is hitting a ``HttpStatus`` of 406 - content unacceptable.  I’ve messed around with the test so that it can accept and expect any/all data but it still hits that 406 error every time.  I know it’s do do with the RestError object of the exception because if I take that out of the ``ResponseEntity`` that is returned by the controller then the expected response status is returned.  Any help on this is appreciated.

</details>


# 答案1
**得分**: 2

从 ``@GetMapping(path = &quot;/{id}/export&quot;, produces = &quot;application/zip&quot;)`` 中删除 produces 部分,
并将其修改为 ``@GetMapping(path = &quot;/{id}/export&quot;)``。

由于在测试用例执行期间会返回 406 错误,
如果删除此部分,您将获得您正在抛出的确切错误。

但是,请检查是否如预期般下载了 zip 文件。

<details>
<summary>英文:</summary>

Remove the produces from  ``@GetMapping(path = &quot;/{id}/export&quot;, produces = &quot;application/zip&quot;)``
and change it to ``@GetMapping(path = &quot;/{id}/export&quot;)``

Due to this during test case execution 406 error is returned
You will get exact error what you are throwing if you remove this.

However check the zip file gets downloaded as expected or not.

</details>



huangapple
  • 本文由 发表于 2020年5月19日 21:07:21
  • 转载请务必保留本文链接:https://go.coder-hub.com/61891813.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定