Модульное тестирование с MockServletContext

Я установил приложение весенней загрузки, используя Gradle. Теперь я понимаю, что @EnableAutoConnfiguration настраивает приложение на основе зависимостей в пути к классам. Я очень счастлив, чтобы избежать всей сантехники, но начинают происходить вещи, которые я бы не хотел.

Вот мои зависимости:

dependencies {
        compile('org.springframework.boot:spring-boot-starter-web:1.2.3.RELEASE')
        compile 'org.springframework.hateoas:spring-hateoas:0.17.0.RELEASE'
        compile 'org.springframework.plugin:spring-plugin-core:1.2.0.RELEASE'
        compile 'org.springframework.boot:spring-boot-starter-data-jpa'

        compile 'com.google.guava:guava:18.0'
        compile 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310'
        compile 'commons-beanutils:commons-beanutils:1.9.2'
        runtime 'org.hsqldb:hsqldb:2.3.2'

        testCompile 'org.springframework.boot:spring-boot-starter-test'
        testCompile 'com.jayway.jsonpath:json-path:2.0.0'
    }

Мой класс приложения:

@ComponentScan("org.home.project")
@SpringBootApplication
//@EnableHypermediaSupport(type = EnableHypermediaSupport.HypermediaType.HAL)
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

Фрагмент из UserController:

@RequestMapping(method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE)
public HttpEntity<ResourceSupport> create(@Valid @RequestBody UserCreateRequest ucr, BindingResult bindingResult) {
    if (bindingResult.hasErrors()) throw new InvalidRequestException("Bad Request", bindingResult);

    Long userId = userService.create(ucr);

    ResourceSupport resource = new ResourceSupport();
    resource.add(linkTo(UserEndpoint.class).withSelfRel());
    resource.add(linkTo(methodOn(UserEndpoint.class).update(userId, null, null)).withRel(VIEW_USER));
    resource.add(linkTo(methodOn(UserEndpoint.class).delete(userId)).withRel(DELETE_USER));

    return new ResponseEntity(resource, HttpStatus.CREATED);
}

UserController.java имеет две аннотации:

@RestController
@RequestMapping(value = "/users", produces = MediaType.APPLICATION_JSON_VALUE)

Прежде всего - обратите внимание на закомментированную аннотацию @EnableHyperdiaSupport - ссылки в экземпляре ResourceSupport по-прежнему сериализуются в формат hal+json, несмотря на то, что тип носителя и тип носителя установлены в запросе. Это происходит автоматически, когда в зависимости вводится org.springframework.plugin:spring-plugin-core:1.2.0.RELEASE. Как можно было бы настроить его явно?

Еще одна проблема - модульные тесты.

Это проходит:

@RunWith(SpringJUnit4ClassRunner.class)
    @SpringApplicationConfiguration(classes = MockServletContext.class)
    @WebAppConfiguration
    public class UserControllerTest {
    ...ommited for brevity...

@InjectMocks
    private UserController testObject;

    @Before
    public void setUp() throws Exception {
        initMocks(this);
        mockMvc = standaloneSetup(testObject).build();
    }

    @Test
        public void testUserCreatedLinks() throws Exception {
            mockMvc.perform(post("/users").contentType(MediaType.APPLICATION_JSON).content(data))
            .andExpect(status().isCreated())
            .andExpect(content().contentType(MediaType.APPLICATION_JSON)).andExpect(jsonPath("$.links.[*].rel", hasItem("self")));
        }
    ...ommited fro brevity...
    }

Запрос post возвращает стандартный ответ JSON в тесте, а не HAL+JSON. Есть ли способ перенастроить это так, чтобы модульное тестирование @RestController с MockServletContext приводило к HAL + JSON или возвращалось к проблеме № 1 - как явно настроить формат ответа, чтобы сериализатор Jackson не производил hal+json?

1 ответ

Решение

Вы запускаете тест с использованием Spring MVC Test standaloneSetup который использует минимум настроек для запуска и запуска вашего контроллера. Эта конфигурация отличается от конфигурации, которая будет использоваться при запуске всего приложения.

Если вы хотите использовать ту же конфигурацию, вы можете использовать webAppContextSetup:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = Application.class)
@WebAppConfiguration
public class SomeTests {

    @Autowired
    private WebApplicationContext context;

    private MockMvc mockMvc;

    @Before
    public void setUp() {
        this.mockMvc = MockMvcBuilders.webAppContextSetup(this.context).build();
    }
}

Кроме того, вы можете скопировать конфигурацию Spring HATEOAS в автономной установке. Обратите внимание, что это может привести к отклонению конфигурации ваших тестов от конфигурации вашего приложения. Вы бы создали MockMvc например, как это:

TypeConstrainedMappingJackson2HttpMessageConverter messageConverter = 
            new TypeConstrainedMappingJackson2HttpMessageConverter(ResourceSupport.class);
messageConverter.setSupportedMediaTypes(Arrays.asList(MediaTypes.HAL_JSON));

ObjectMapper objectMapper = messageConverter.getObjectMapper();
objectMapper.registerModule(new Jackson2HalModule());
objectMapper.setHandlerInstantiator(
        new Jackson2HalModule.HalHandlerInstantiator(new DefaultRelProvider(), null));

MockMvc mockMvc = MockMvcBuilders.standaloneSetup(testObject)
        .setMessageConverters(messageConverter).build();
Другие вопросы по тегам