Spring MVC控制器调用REST API的错误单元测试

时间:2015-10-30 18:07:44

标签: spring spring-mvc spring-restcontroller spring-mvc-test

我在我的小应用程序中对spring MVC控制器进行单元测试,但收到以下错误:

INFO: **Initializing Spring FrameworkServlet ''**
Oct 30, 2015 5:37:38 PM org.springframework.test.web.servlet.TestDispatcherServlet initServletBean
INFO: FrameworkServlet '': initialization started
Oct 30, 2015 5:37:38 PM org.springframework.test.web.servlet.TestDispatcherServlet initServletBean
INFO: FrameworkServlet '': initialization completed in 2 ms
Running com.sky.testmvc.product.controller.ProductSelectionControllerTest
Tests run: 1, Failures: 1, Errors: 0, Skipped: 0, Time elapsed: 0.031 sec <<< FAILURE!
testRoot(com.sky.testmvc.product.controller.ProductSelectionControllerTest)  Time elapsed: 0.031 sec  <<< FAILURE!
*java.lang.AssertionError: **Status expected:<200> but was:<204>***
    at org.springframework.test.util.AssertionErrors.fail(AssertionErrors.java:60)
    at org.springframework.test.util.AssertionErrors.assertEquals(AssertionErrors.java:89)
    at org.springframework.test.web.servlet.result.StatusResultMatchers$5.match(StatusResultMatchers.java:549)
    at org.springframework.test.web.servlet.MockMvc$1.andExpect(MockMvc.java:141)

其余控制器如下:

 @RestController
    public class ItemRestController {   

        @Autowired
        ItemService catalogueService;   
        @Autowired
        LocationService locationService;   

        @RequestMapping(value = "/product/{customerId}", produces = {MediaType.APPLICATION_JSON_VALUE}, method = RequestMethod.GET)
        public ResponseEntity<List<Item>> listCustomerProducts(@PathVariable("customerId") int customerId) {

            Integer customerLocation=(Integer) locationService.findLocationByCustomerId(customerId);
            List<Product> products = catalogueService.findCustomerProducts(customerLocation);

            if(products.isEmpty()){
                return new ResponseEntity<List<Product>>(HttpStatus.NO_CONTENT);
            }
            return new ResponseEntity<List<Product>>(products, HttpStatus.OK);
        }   
    }



  @RunWith(SpringJUnit4ClassRunner.class)
    @WebAppConfiguration
    @ContextConfiguration(classes = {TestContext.class, AppConfiguration.class}) //load your mvc config classes here

    public class ItemControllerTest {

        private MockMvc mockMvc;
        @Autowired
        private ItemService productServiceMock;
        @Autowired
        private WebApplicationContext webApplicationContext;

        @Before
        public void setUp() {
            Mockito.reset(productServiceMock);
            mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
        }



  @Test
public void testRoot() throws Exception 
{      

    Product prod1= new Product(1L,"Orange", new ProductCategory(1,"Sports"),new CustomerLocation(2,"London"));
    Product prod2= new Product(2L,"Banana", new ProductCategory(1,"Sports"),new CustomerLocation(2,"London"));

    when(productServiceMock.findCustomerProducts(1L)).thenReturn(Arrays.asList(prod1, prod2));

    mockMvc.perform(get("/product/{id}", 1L))
    .andExpect(status().isOk())
    .andExpect(content().contentType(TestUtil.APPLICATION_JSON_UTF8))
    .andExpect(jsonPath("$", hasSize(2)))
            .andExpect(jsonPath("$[0].productId", is(1)))
            .andExpect(jsonPath("$[0].productName", is("Orange")))
            .andExpect(jsonPath("$[1].productId", is(2)))
            .andExpect(jsonPath("$[1].productName", is("Banana")));

    verify(productServiceMock, times(1)).findCustomerProducts(1L);
    verifyNoMoreInteractions(productServiceMock);       
}

    }

请参阅下面的TestContext:

 @Configuration
    public class TestContext {

        private static final String MESSAGE_SOURCE_BASE_NAME = "i18n/messages";

        @Bean
        public MessageSource messageSource() {
            ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();

            messageSource.setBasename(MESSAGE_SOURCE_BASE_NAME);
            messageSource.setUseCodeAsDefaultMessage(true);

            return messageSource;
        }

        @Bean
        public ItemService catalogueService() {
            return Mockito.mock(ItemService .class);
        }
    }


 @Configuration
    @EnableWebMvc
    @ComponentScan(basePackages = "com.uk.springmvc")
    public class AppConfiguration extends WebMvcConfigurerAdapter{

        private static final String VIEW_RESOLVER_PREFIX = "/WEB-INF/views/";
        private static final String VIEW_RESOLVER_SUFFIX = ".jsp";


        @Override
        public void configureViewResolvers(ViewResolverRegistry registry) {
            InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
            viewResolver.setViewClass(JstlView.class);
            viewResolver.setPrefix(VIEW_RESOLVER_PREFIX);
            viewResolver.setSuffix(VIEW_RESOLVER_SUFFIX);
            registry.viewResolver(viewResolver);
        }

        @Override
        public void addResourceHandlers(ResourceHandlerRegistry registry) {
            registry.addResourceHandler("/static/**").addResourceLocations("/static/");
        }

        @Override
        public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
            configurer.enable();
        }

        @Bean
        public SimpleMappingExceptionResolver exceptionResolver() {
            SimpleMappingExceptionResolver exceptionResolver = new SimpleMappingExceptionResolver();

            Properties exceptionMappings = new Properties();

            exceptionMappings.put("java.lang.Exception", "error/error");
            exceptionMappings.put("java.lang.RuntimeException", "error/error");

            exceptionResolver.setExceptionMappings(exceptionMappings);

            Properties statusCodes = new Properties();

            statusCodes.put("error/404", "404");
            statusCodes.put("error/error", "500");

            exceptionResolver.setStatusCodes(statusCodes);

            return exceptionResolver;
        }


    }

如前所述,应用程序正常工作,我可以读取通过浏览器返回的json,并将其显示在我的angularjs视图中,但是单元测试不起作用。错误是java.lang.AssertionError:预期的状态:&lt; 200&gt;但是:&lt; 204&gt;。 204 - 回复是空的...... 可以是&gt; 初始化Spring FrameworkServlet&#39; 即框架servlet未初始化?不确定。 任何帮助将不胜感激

My Rest Coontroller

@RestController 公共类ItemRestController {

@Autowired
ItemService catalogueService;  //Service which will do product retrieval

@Autowired
LocationService locationService;  //Service which will retrieve customer location id using customer id

//-------------------Retrieve All Customer Products--------------------------------------------------------

@RequestMapping(value = "/product/{customerId}", produces = {MediaType.APPLICATION_JSON_VALUE}, method = RequestMethod.GET)
public ResponseEntity<List<Product>> listCustomerProducts(@PathVariable("customerId") int customerId) {

    Integer customerLocation=(Integer) locationService.findLocationByCustomerId(customerId);
    List<Product> products = catalogueService.findCustomerProducts(customerLocation);

    if(products.isEmpty()){
        return new ResponseEntity<List<Product>>(HttpStatus.NO_CONTENT);
    }
    return new ResponseEntity<List<Product>>(products, HttpStatus.OK);
}

}

2 个答案:

答案 0 :(得分:0)

正如我们从堆栈跟踪中看到的那样,由于断言错误,测试失败:它期望HTTP状态200,但得到204,即HTTPStatus.NO_CONTENT,您返回在列表为空时在控制器中。

        if(products.isEmpty()){
            return new ResponseEntity<List<Product>>(HttpStatus.NO_CONTENT);
        }

如果您希望控制器返回200,则需要使用CatalogueService模拟返回某些内容...

答案 1 :(得分:0)

In your test, you are mocking ItemService (using productServiceMock), but your controller is calling instance of CatalogueService

Also make sure your mocks are properly injected, debugger is really your best friend here. I guess from your syntax, that you are using Mockito. In such case, mocked object have "$$EnhancedByMockito" in their getClass().getName() method