O MockMvc não lida mais com caracteres UTF-8 com o Spring Boot 2.2.0.

14

Depois de atualizar para a 2.2.0.RELEASEversão recém-lançada do Spring Boot, alguns dos meus testes falharam. Parece que MediaType.APPLICATION_JSON_UTF8foi preterido e não é mais retornado como tipo de conteúdo padrão dos métodos do controlador que não especificam o tipo de conteúdo explicitamente.

Código de teste como

String content = mockMvc.perform(get("/some-api")
            .contentType(MediaType.APPLICATION_JSON))
            .andExpect(status().isOk())
            .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8))
            .andReturn()
            .getResponse()
            .getContentAsString();

de repente não funcionou mais, pois o tipo de conteúdo era incompatível, como mostrado abaixo

java.lang.AssertionError: Content type 
Expected :application/json;charset=UTF-8
Actual   :application/json

Alterando o código para .andExpect(content().contentType(MediaType.APPLICATION_JSON))o problema resolvido por enquanto.

Mas agora, ao comparar contentcom o objeto serializado esperado, ainda há uma incompatibilidade se houver algum caractere especial no objeto. Parece que o .getContentAsString()método não utiliza a codificação de caracteres UTF-8 por padrão (mais nada).

java.lang.AssertionError: Response content expected:<[{"description":"Er hörte leise Schritte hinter sich."}]> but was:<[{"description":"Er hörte leise Schritte hinter sich."}]>
Expected :[{"description":"Er hörte leise Schritte hinter sich."}]
Actual   :[{"description":"Er hörte leise Schritte hinter sich."}]

Como posso obter a contentcodificação UTF-8?

Vezes
fonte

Respostas:

7

Sim. Este é um problema do 2.2.0 spring-boot. Eles configuram a descontinuação para a codificação de conjunto de caracteres padrão.

.getContentAsString(StandardCharsets.UTF_8) - bom, mas em qualquer resposta seria preenchida a ISO 8859-1 por padrão.

No meu projeto, atualizei o conversor criado atual:

@Configuration
public class SpringConfig implements WebMvcConfigurer {

    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        converters.stream()
            .filter(converter -> converter instanceof MappingJackson2HttpMessageConverter)
            .findFirst()
            .ifPresent(converter -> ((MappingJackson2HttpMessageConverter) converter).setDefaultCharset(UTF_8));
    }
...
Alexander Someoneperson
fonte
Esta foi a solução mais fácil recomendada aqui!
Times
você salvou meu dia!
Filomat 22/02
2

O caractere de codificação padrão não é mais UTF-8 desde a versão 5.2.0 do spring.

Para continuar usando o UTF-8, você deve configurá-lo no ServletResponse do resultado do MockMvc. Para definir a codificação de caracteres padrão como UTF-8, faça algo assim no seu método de configuração:

@Before
public void setUp() {
   mockMvc = webAppContextSetup(wac).addFilter(((request, response, chain) -> {
                response.setCharacterEncoding("UTF-8");
                chain.doFilter(request, response);
            })).build();
}

Em seguida, você pode usar a instância mockMvc para executar sua solicitação.

Espero que esta ajuda.

black4bird
fonte
Com esta solução, eu teria que configurar o mockMvc em todas as classes de teste. Isso pode ser bastante entediante para muitas classes de teste!
Times
0

De acordo com essa solicitação de recebimento dos desenvolvedores da primavera, o cabeçalho UTF-8 não é mais necessário e, portanto, está obsoleto. Se você estiver usando o cabeçalho UTF-8 em seu aplicativo, considere removê-lo do seu aplicativo em vez de tentar corrigir seu teste. Apenas certifique-se de usar o cabeçalho application-json / Content-Type: e você deve estar bem.

scre_www
fonte
Eu acho que você não entende o problema. Sugiro que você leia a pergunta toda e depois reavalie, se sua resposta oferecer algum valor. Minha aplicação está funcionando perfeitamente bem, o problema está relacionado aos testes.
Times
Li a pergunta toda novamente e reavaliei minha resposta, a resposta ainda é a mesma. Na sua pergunta, você não explica por que o cabeçalho foi descontinuado. Eu a enriqueci com a minha postagem. Sugiro que você leia o PR ao qual vinculei, para entender por que o cabeçalho foi descontinuado. Se você entender o porquê, convém alterar seu teste, pois ele está testando o comportamento padrão no Spring 2.1.X, mas ele não testa o comportamento no Spring 2.2.X corretamente. O comportamento do Spring mudou, seu teste deve mudar de acordo se você aceitar o novo comportamento do Spring.
Scre_www 01/12/19
Você não está sendo muito consistente aqui. Na sua resposta, você diz "[...] em vez de tentar corrigir seu teste". No seu comentário, você diz que "[...] seu teste deve mudar de acordo se você aceitar o novo comportamento do Spring".
Times
Todo programador enfrenta valores obsoletos de vez em quando. Quando algo é preterido, você pode corrigi-lo de alguma forma sem pesquisar por que ele foi preterido. Essa abordagem parece ser a maneira como você está lidando com esse problema. Agora, sugiro que você procure mais e pesquise por que isso foi preterido. Se você entender isso, poderá tomar uma decisão melhor sobre o que fazer a seguir. Na sua pergunta, não há nada sobre o motivo pelo qual você apenas nos diz que seu teste está falhando devido a um valor descontinuado, que é uma pesquisa fraca. Enriquei a pergunta com algumas pesquisas que você não fez E votou positivamente no Q.
scre_www
0

Estou usando o Spring Boot 1.5.15.RELEASE e enfrentou o mesmo problema ao escrever testes.

A primeira solução que me ajudou foi adicionar .characterEncoding ("UTF-8")) assim:

String content = mockMvc.perform(get("/some-api")
            .contentType(MediaType.APPLICATION_JSON)
            .characterEncoding("UTF-8"))
            .andExpect(status().isOk())
            .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8))
            .andReturn()
            .getResponse()
            .getContentAsString();

Estou usando um StandaloneMockMvcBuilder na minha classe de teste, então a segunda solução que me ajudou foi a criação de um filtro, por exemplo:

private static class Utf8Filter extends OncePerRequestFilter {

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
        throws ServletException, IOException {
        response.setCharacterEncoding(StandardCharsets.UTF_8.toString());
        filterChain.doFilter(request, response);
    }
}

e depois adicione-o ao método standaloneSetup na minha classe de teste, assim:

@Before
public void setup() {
    MockitoAnnotations.initMocks(this);
    final SomeResource someResource = new SomeResource(someService);
    this.restLankMockMvc = MockMvcBuilders.standaloneSetup(someResource)
        .setCustomArgumentResolvers(pageableArgumentResolver)
        .setControllerAdvice(exceptionTranslator)
        .setConversionService(createFormattingConversionService())
        .setMessageConverters(jacksonMessageConverter)
        .addFilter(new Utf8Filter())
        .build();
}
Zuljen
fonte
0

Configuração adicional para MockMvc .accept(MediaType.APPLICATION_JSON_UTF8_VALUE):

    String content = mockMvc.perform(get("/some-api")
        .contentType(MediaType.APPLICATION_JSON)
        .accept(MediaType.APPLICATION_JSON_UTF8_VALUE))
        .andExpect(status().isOk())
        .andExpect(content().contentType(MediaType.APPLICATION_JSON))
        .andReturn()
        .getResponse()
        .getContentAsString();

Esse problema não é o Spring Boot, mas sim o MockMvc, eu acho. Portanto, uma solução alternativa deve ser aplicada apenas ao MockMvc. ( JSON deve ser codificado usando UTF-8 .)

problema relacionado: Manuseio inadequado de UTF-8 no MockMvc para resposta JSON · Edição nº 23622 · spring-projects / spring-framework

yukihane
fonte