2014-10-16 7 views
4

Я пытаюсь закодировать единичный тест для метода, определенного в контроллере. Метод таков:Тестирование модуля с использованием функции DomainClassConverter Spring

@RestController 
@RequestMapping("/products") 
public class RestProductController { 

@RequestMapping(value="/{product}/skus", produces = MediaType.APPLICATION_JSON_VALUE, method = RequestMethod.GET) 
    public List<SkuSummaryVO> getSkuByProduct(@Valid @PathVariable Product product){ 
     List<SkuSummaryVO> skusByProductVOs = skuService.getSkusByProduct(product); 
     return skusByProductVOs; 
    } 
} 

Мы используем в нашем классе Configuration аннотаций @EnableSpringDataWebSupport, чтобы включить функцию DomainClassConverter. Таким образом, мы можем использовать объект JPA как @PathVariable. Поэтому, когда идентификатор продукта будет указан в URL-адресе, мы получим продукт (с запросом за сценой).

Мы разрабатываем единичный тест без включения контекста приложения Spring и использования Mockito. Таким образом, мы инициализируем mockMvcBuilders так:

public class RestProductControllerTest { 

    ... 

    @Before 
    public void setUp() { 
     RestProductController restProductController = new RestProductController(); 
     ... 
     mockMvc = MockMvcBuilders.standaloneSetup(restProductController).build(); 
    } 
} 

и метод испытания, как это:

@Test 
    public void testGetProductById() throws Exception { 
     ... 
     String jsonResult = ...;  
     mockMvc.perform(get("/products/123/skus").contentType(MediaType.APPLICATION_JSON)).andExpect(status().isOk()).andExpect(content().string(jsonResult)); 
    } 

И я получаю 500 для HttpCode (статус)

И блок тесты отлично работают для методов контроллера, которые не используют функцию DomainClassConverter (например, если я использую Long productId вместо Product product в качестве параметра getSkuByProduct, он будет работать)

ответ

2

UPDATE: на второй мысли, что я первоначально предложенный ниже никогда не мог работать, так как DomainClassConverter требует, чтобы ваши Spring Хранилища данных присутствовать в ApplicationContext, и в вашем примере вы используете StandaloneMockMvcBuilder, который никогда не будет создавать ApplicationContext, который содержит ваши хранилища данных Spring.

Как я вижу, у вас есть два варианта.

  1. Преобразование теста на интеграционный тест с использованием реального ApplicationContext (загружается через @ContextConfiguration, как показано в справочном руководстве) и передать в MockMvcBuilders.webAppContextSetup(WebApplicationContext). Если сконфигурированный ApplicationContext включает в себя веб-конфигурацию Spring Data, вам должно быть хорошо идти.
  2. Отказаться от использования DomainClassConverter в вашем модульном тесте и вместо этого установить HandlerMethodArgumentResolver (например, заглушку или макет) через StandaloneMockMvcBuilder.setCustomArgumentResolvers(HandlerMethodArgumentResolver...). Ваш пользовательский резольвер мог бы вернуть нужный вам нужный Product экземпляр.

Вы должны зарегистрировать экземпляр DomainClassConverter с ConversionService в StandaloneMockMvcBuilder, который создается при вызове MockMvcBuilders.standaloneSetup(Object...).

В SpringDataWebConfiguration.registerDomainClassConverterFor(), вы можете увидеть, что DomainClassConverter экземпляр (и косвенно зарегистрирован), как это:

DomainClassConverter<FormattingConversionService> converter = 
    new DomainClassConverter<FormattingConversionService>(conversionService); 
converter.setApplicationContext(context); 

И вы можете настроить свой собственный FormattingConversionService через StandaloneMockMvcBuilder.setConversionService(). См. WebMvcConfigurationSupport.mvcConversionService() для примера того, как настроить ConversionService для веб-среды.

Задача тогда заключается в том, как получить ссылку на ApplicationContext.Внутренне, StandaloneMockMvcBuilder использует StubWebApplicationContext, но, насколько я могу видеть (до Spring 4.1), нет доступа к нему напрямую без подкласса StandaloneMockMvcBuilder.

По Spring Framework 4.1, можно реализовать пользовательские MockMvcConfigurer (который дает вам доступ к WebApplicationContext через его метод beforeMockMvcCreated().

Так, мы надеемся, что это достаточно информации, чтобы вы на правильном пути!

Удачи ...

Сэм

+0

мы изменили код, и мы не используем DomainClassConverter anymore.we имеют отношение '@ ManyToOne' к' Product' от 'Sku' лица и мы только что обнаружили, что в Spring data JPA мы можем получить доступ к продукту только с идентификатором (а не с полным объектом продукта, поэтому не более «DomainClassConverter»), используя специальные ключевые слова для имени метода: 'findByProductId' в нашем интерфейсе репозитория (witch extends JpaRepository). С помощью «DomainClassConverter» используемым методом был «findByProduct». В документе doc данных Spring они говорят о имени ключевых слов метода, но его не ясно, когда мы имеем отношение между объектами. –

+0

Но в противном случае мы пошли бы к вашему методу 1. Но спасибо за ваш четкий ответ. –

+0

Вы очень желанны. И я рад, что вы нашли более чистое решение с подходом 'findByProductId()'! –