2015-12-08 2 views
2

Я написал небольшой тест в документах Spring REST с пользовательским модулем Jackson (используя Spring Boot 1.3). В моем основном классе приложений у меня есть только @SpringBootApplication. Я тогда еще один класс JacksonCustomizations который выглядит следующим образом:Пользовательский модуль Jackson не используется в Spring REST docs test

@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.
+0

Вы пытались добавить класс @Import (JacksonCustomizations.class) в класс NoteControllerDocumentation? – reos

+0

@reos не имеет значения –

+0

Похоже, Spring Boot не настроил автоматическую настройку «ObjectMapper» с помощью вашего собственного «модуля». Это соответствует тому, что вы не предоставили «SpringApplicationConfiguration» классу (-ам) для вашего приложения, поэтому Spring Boot не знает, что делать. Фактически, код, который вы разделили, с ошибкой «IllegalStateException», который говорит «Нет классов конфигурации или местоположений, найденных в @SpringApplicationConfiguration» из-за этого. Можете ли вы поделиться небольшим образцовым проектом, который содержит точный код, который вы запускаете, чтобы вызвать проблему? –

ответ

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(); 
     } 

    } 

} 
+0

Но что, если мой контроллер использует автосервисную службу или репозиторий? Как я могу настроить для этого макет? Ссылка на «DemoApplication» будет включать реальные службы/репозитории. –

+0

Вы не упомянули это требование в вопросе, поэтому я не обращался к нему.Я обновил свой ответ с подробностями другого подхода. –

Смежные вопросы