需求描述

在 Junit 使用 MockMvc 对 Controller 层进行单元测试时,发现控制台打印的响应结果中文出现乱码,导致断言异常(预期值与结果不符)。

解决方案

这是由于 spring 默认字符集为 ISO-8859-1,中文无法被正确的识别。因此只要能够重新设置支持中文的字符集即可解决该问题。

修改 Servlet 配置

虽然使用 spring boot 预留的配置可以轻松的解决问题,但是粒度太粗了,一旦设置全局生效,唯一值得庆幸的是,此处需要设置的是字符集,大部分场景下都会使用 UFT-8。

1
2
3
4
5
6
7
server:
servlet:
encoding:
charset: UTF-8
enabled: true
# 确保响应值被重置字符集
force-response: true

重写输出方法

不要使用 MockMvcResultHandlers.print()方法输出响应结果,重新实现 ResultHandler接口。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
public class ForceCharsetPrintingResultHandler extends PrintingResultHandler {

private static final String DEFAULT_CHARSET = "UTF-8";

/**
* UTF-8 字符集的结果打印处理器
*/
public static final ForceCharsetPrintingResultHandler UTF_8PrintingResultHandler = new ForceCharsetPrintingResultHandler(DEFAULT_CHARSET);

private final String defaultCharset;

public ForceCharsetPrintingResultHandler(String defaultCharset) {
super(new ResultValuePrinter() {

@Override
public void printHeading(@NotNull String heading) {
System.out.println();
System.out.printf("%s:%n", heading);
}

@Override
public void printValue(@NotNull String label, Object value) {
if (value != null && value.getClass().isArray()) {
value = CollectionUtils.arrayToList(value);
}
System.out.printf("%17s = %s%n", label, value);
}

});
this.defaultCharset = defaultCharset;
}

@Override
protected void printRequest(MockHttpServletRequest request) throws Exception {
request.setCharacterEncoding(defaultCharset);
super.printRequest(request);
}

@Override
protected void printResponse(MockHttpServletResponse response) throws Exception {
response.setCharacterEncoding(defaultCharset);
super.printResponse(response);
}

}
1
2
3
mockMvc.perform()
// .andDo(MockMvcResultHandlers.print())
.andDo(ForceCharsetPrintingResultHandler.UTF_8PrintingResultHandler)

评论