自定义Jackson模块未在Spring REST docs测试中使用

时间:2015-12-08 13:17:24

标签: java spring spring-mvc spring-boot spring-restdocs

我已经使用自定义Jackson模块(使用Spring Boot 1.3)编写了一个关于Spring REST文档的小测试。在我的应用程序主类中,我只有@SpringBootApplication。然后,我有另一个类JacksonCustomizations,如下所示:

@Configuration
public class JacksonCustomizations {

@Bean
public Module myCustomModule() {
    return new MyCustomModule();
}

static class MyCustomModule extends SimpleModule {
    public MyCustomModule() {

        addSerializer(ImmutableEntityId.class, new JsonSerializer<ImmutableEntityId>() {
            @Override
            public void serialize(ImmutableEntityId immutableEntityId, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException, JsonProcessingException {
                jsonGenerator.writeNumber( (Long)immutableEntityId.getId() );
            }
        });
    }
}
}

这种自定义功能完美无缺。当我运行Spring Boot应用程序时,我会看到它应该是JSON。

但是,在我的文档测试中,未应用自定义。这是我测试的代码:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration
@WebAppConfiguration
public class NoteControllerDocumentation {

@Rule
public final RestDocumentation restDocumentation = new RestDocumentation("target/generated-snippets");

@Autowired
private WebApplicationContext context;

private MockMvc mockMvc;

@Before
public void setUp() throws Exception {
    mockMvc = MockMvcBuilders.webAppContextSetup(context)
                             .apply(documentationConfiguration(restDocumentation))
                             .build();

}


@Test
public void notesListExample() throws Exception {
    mockMvc.perform(get("/api/notes/"))
           .andExpect(status().isOk())
           .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8))
           .andDo(document("notes-list-example", responseFields(
                   fieldWithPath("[]").description("An array of <<note-example,note>>s."))));
}

@Configuration
@EnableWebMvc
@Import(JacksonCustomizations.class)
public static class TestConfiguration {
    @Bean
    public NoteController noteController() {
        return new NoteController();
    }
}

}

请注意我的测试中的应用程序上下文如何导入JacksonCustomizations配置。

我发现的其他事情:

  • 在我的启动应用程序上添加@EnableWebMvc会停止自定义工作。
  • 删除测试中的@EnableWebMvc会停止生成JSON。

1 个答案:

答案 0 :(得分:1)

NoteControllerDocumentation未配置为使用Spring Boot创建应用程序上下文。这意味着Spring Boot的自动配置不会运行,因此,您的自定义Jackson模块不会应用于ObjectMapper

解决您问题的最简单方法是删除TestConfiguration课程,然后将SpringApplicationConfiguration更新为引用DemoApplication。这将留下以下代码:

package com.example.controller;

import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;
import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.documentationConfiguration;
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get;
import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;
import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.http.MediaType;
import org.springframework.restdocs.RestDocumentation;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;

import com.example.DemoApplication;

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = DemoApplication.class)
@WebAppConfiguration
public class NoteControllerDocumentation {

    @Rule
    public final RestDocumentation restDocumentation = new RestDocumentation("target/generated-snippets");

    @Autowired
    private WebApplicationContext context;

    private MockMvc mockMvc;

    @Before
    public void setUp() throws Exception {
        mockMvc = MockMvcBuilders.webAppContextSetup(context)
                                 .apply(documentationConfiguration(restDocumentation))
                                 .build();

    }

    @Test
    public void notesListExample() throws Exception {
        mockMvc.perform(get("/api/notes/"))
               .andExpect(status().isOk())
               .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8))
               .andExpect(content().json("[{\"id\":1}]"))
               .andDo(print())
               .andDo(document("nodes-list-example", responseFields(
                       fieldWithPath("[]").description("An array of <<note-example,note>>s."))));
    }

}

或者,如果您想要更好地控制控件的创建方式(例如,注入模拟服务),则可以使用自定义配置类。关键是使用@EnableAutoConfiguration注释该类,以便启用Spring Boot的自动配置并执行ObjectMapper的自定义。这种方法将为您提供以下代码:

package com.example.controller;

import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;
import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.documentationConfiguration;
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get;
import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;
import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.http.MediaType;
import org.springframework.restdocs.RestDocumentation;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;

import com.example.JacksonCustomizations;

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration
@WebAppConfiguration
public class NoteControllerDocumentation {

    @Rule
    public final RestDocumentation restDocumentation = new RestDocumentation("target/generated-snippets");

    @Autowired
    private WebApplicationContext context;

    private MockMvc mockMvc;

    @Before
    public void setUp() throws Exception {
        mockMvc = MockMvcBuilders.webAppContextSetup(context)
                                 .apply(documentationConfiguration(restDocumentation))
                                 .build();

    }

    @Test
    public void notesListExample() throws Exception {
        mockMvc.perform(get("/api/notes/"))
               .andExpect(status().isOk())
               .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8))
               .andExpect(content().json("[{\"id\":1}]"))
               .andDo(print())
               .andDo(document("nodes-list-example", responseFields(
                       fieldWithPath("[]").description("An array of <<note-example,note>>s."))));
    }

    @Configuration
    @EnableAutoConfiguration
    @Import(JacksonCustomizations.class)
    static class TestConfiguration {

        @Bean
        public NoteController notesController() {
            return new NoteController();
        }

    }

}