代码之家  ›  专栏  ›  技术社区  ›  Brandon Yarbrough

测试Spring@MVC注释

  •  9
  • Brandon Yarbrough  · 技术社区  · 16 年前

    前几天我遇到了一个问题,@Valid注释被意外地从控制器类中删除。不幸的是,它没有破坏我们的任何测试。我们的单元测试中没有一个实际使用弹簧 AnnotationMethodHandlerAdapter 通路。我们只是直接测试我们的控制器类。

    如果@MVC注释错误,我如何编写一个单元或集成测试将正确失败?有没有一种方法可以让Spring使用MockHttpServlet或其他工具来查找和练习相关的控制器?

    3 回复  |  直到 16 年前
        1
  •  1
  •   Janning Vygen    14 年前

    在即将到来的Spring3.2(快照可用)或SpringTestMVC中(https://github.com/SpringSource/spring-test-mvc)您可以这样做:

    首先,我们模拟验证,因为我们不想测试验证器,只想知道是否调用了验证。

    public class LocalValidatorFactoryBeanMock extends LocalValidatorFactoryBean
    {
        private boolean fakeErrors;
    
        public void fakeErrors ( )
        {
            this.fakeErrors = true;
        }
    
        @Override
        public boolean supports ( Class<?> clazz )
        {
            return true;
        }
    
        @Override
        public void validate ( Object target, Errors errors, Object... validationHints )
        {
            if (fakeErrors)
            {
                errors.reject("error");
            }
        }
    }
    

    这是我们的测试课:

    @RunWith(SpringJUnit4ClassRunner.class)
    @WebAppConfiguration
    @ContextConfiguration
    public class RegisterControllerTest
    {
     @Autowired
     private WebApplicationContext  wac;
     private MockMvc mockMvc;
    
         @Autowired
         @InjectMocks
         private RegisterController registerController;
    
         @Autowired
         private LocalValidatorFactoryBeanMock  validator;
    
      @Before
      public void setup ( )
      {
         this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
         // if you want to inject mocks into your controller
                 MockitoAnnotations.initMocks(this);
      }
    
        @Test
        public void testPostValidationError ( ) throws Exception
        {
            validator.fakeErrors();
            MockHttpServletRequestBuilder post = post("/info/register");
            post.param("name", "Bob");
            ResultActions result = getMockMvc().perform(post);
                // no redirect as we have errors
            result.andExpect(view().name("info/register"));
        }
    
        @Configuration
        @Import(DispatcherServletConfig.class)
        static class Config extends WebMvcConfigurerAdapter
        {
            @Override
            public Validator getValidator ( )
            {
                return new LocalValidatorFactoryBeanMock();
            }
    
            @Bean
            RegisterController registerController ( )
            {
                return new RegisterController();
            }
        }
    }
    
        2
  •  13
  •   scarba05    16 年前

    public class MyForm {
        @NotNull
        private Long myNumber;
    
        ...
    }
    

    @Controller
    @RequestMapping("/simple-form")
    public class MyController {
        private final static String FORM_VIEW = null;
    
        @RequestMapping(method = RequestMethod.POST)
        public String processFormSubmission(@Valid MyForm myForm,
                BindingResult result) {
            if (result.hasErrors()) {
                return FORM_VIEW;
            }
            // process the form
            return "success-view";
        }
    }
    

    您需要测试@Valid和@NotNull注释是否正确连接:

    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration({"file:web/WEB-INF/application-context.xml",
        "file:web/WEB-INF/dispatcher-servlet.xml"})
    public class MyControllerIntegrationTest {
    
        @Inject
        private ApplicationContext applicationContext;
    
        private MockHttpServletRequest request;
        private MockHttpServletResponse response;
        private HandlerAdapter handlerAdapter;
    
        @Before
        public void setUp() throws Exception {
            this.request = new MockHttpServletRequest();
            this.response = new MockHttpServletResponse();
    
            this.handlerAdapter = applicationContext.getBean(HandlerAdapter.class);
        }
    
        ModelAndView handle(HttpServletRequest request, HttpServletResponse response)
                throws Exception {
            final HandlerMapping handlerMapping = applicationContext.getBean(HandlerMapping.class);
            final HandlerExecutionChain handler = handlerMapping.getHandler(request);
            assertNotNull("No handler found for request, check you request mapping", handler);
    
            final Object controller = handler.getHandler();
            // if you want to override any injected attributes do it here
    
            final HandlerInterceptor[] interceptors =
                handlerMapping.getHandler(request).getInterceptors();
            for (HandlerInterceptor interceptor : interceptors) {
                final boolean carryOn = interceptor.preHandle(request, response, controller);
                if (!carryOn) {
                    return null;
                }
            }
    
            final ModelAndView mav = handlerAdapter.handle(request, response, controller);
            return mav;
        }
    
        @Test
        public void testProcessFormSubmission() throws Exception {
            request.setMethod("POST");
            request.setRequestURI("/simple-form");
            request.setParameter("myNumber", "");
    
            final ModelAndView mav = handle(request, response);
            // test we're returned back to the form
            assertViewName(mav, "simple-form");
            // make assertions on the errors
            final BindingResult errors = assertAndReturnModelAttributeOfType(mav, 
                    "org.springframework.validation.BindingResult.myForm", 
                    BindingResult.class);
            assertEquals(1, errors.getErrorCount());
            assertEquals("", errors.getFieldValue("myNumber"));        
        }
    

    请参阅我的博客文章 integration testing Spring's MVC annotations

        3
  •  3
  •   skaffman    16 年前

    DispatcherServlet ,将容器中的各种物品注入其中(例如。 ServletContext

    Spring附带了各种与servlet相关的 MockXYZ MockServletContext , MockHttpServletRequest 和 MockHttpServletResponse

    servlet的测试上下文将包含通常与MVC相关的bean,以及要测试的bean。一旦servlet被初始化,创建模拟请求和响应,并将它们提供给servlet的 service() 方法。如果请求被正确路由,您可以检查写入模拟响应的结果。

    推荐文章