使用Spring的DomainClassConverter功能进行单元测试

时间:2014-10-16 09:09:53

标签: java spring-mvc junit spring-data-jpa spring-test

我正在尝试为控制器中定义的方法编写单元测试代码。 方法是这样的:

@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中设置产品ID时,我们将获得产品(在场景后面有请求)。

我们正在开发单元测试而不启用Spring App Context并使用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));
    }

我获得了HttpCode的500(状态)

单元测试对于没有使用DomainClassConverter功能的控制器方法工作正常(例如,如果我使用Long productId而不是Product product作为getSkuByProduct的参数,它会工作)

2 个答案:

答案 0 :(得分:2)

更新:第二个想法,我最初提出的内容永远无法工作,因为DomainClassConverter要求您的Spring数据存储库出现在ApplicationContext中,并且在您的示例中您正在使用永远不会创建包含Spring数据存储库的StandaloneMockMvcBuilder的{​​{1}}。

我看到它的方式,你有两种选择。

  1. 使用真实ApplicationContext(通过ApplicationContext加载,如参考手册中所示)将测试转换为集成测试,并将其传递给@ContextConfiguration。如果配置的MockMvcBuilders.webAppContextSetup(WebApplicationContext)包含您的Spring Data Web配置,那么您应该很高兴。
  2. 放弃在单元测试中使用ApplicationContext,而是通过DomainClassConverter设置自定义HandlerMethodArgumentResolver(例如,存根或模拟)。然后,您的自定义解析程序可以返回您想要的任何StandaloneMockMvcBuilder.setCustomArgumentResolvers(HandlerMethodArgumentResolver...)实例。

  3. 您必须在调用Product时创建的DomainClassConverter中注册ConversionService的{​​{1}}实例。

    StandaloneMockMvcBuilder中,您可以看到MockMvcBuilders.standaloneSetup(Object...)被实例化(并间接注册),如下所示:

    SpringDataWebConfiguration.registerDomainClassConverterFor()

    您可以通过DomainClassConverter设置自己的DomainClassConverter<FormattingConversionService> converter = new DomainClassConverter<FormattingConversionService>(conversionService); converter.setApplicationContext(context); 。有关如何为Web环境配置FormattingConversionService的示例,请参阅StandaloneMockMvcBuilder.setConversionService()

    接下来的挑战是如何获得对WebMvcConfigurationSupport.mvcConversionService()的引用。在内部,ConversionService使用ApplicationContext,但据我所知(在Spring 4.1之前),没有子类化StandaloneMockMvcBuilder就无法直接访问它。

    从Spring Framework 4.1开始,您可以实现自定义StubWebApplicationContext(通过其StandaloneMockMvcBuilder方法,您可以访问MockMvcConfigurer

    希望有足够的信息让你走上正轨!

    祝你好运......

    萨姆

答案 1 :(得分:0)

您可以通过WebConversionService模拟从字符串到实体的转换。查看this答案以获取一些代码示例和更多详细信息。