Pregunta

I corrió en un problema el otro día donde una anotación de @Valid se eliminó accidentalmente de una clase de controlador. Por desgracia, no se rompió ninguna de nuestras pruebas. Ninguna de nuestras pruebas unitarias realmente ejercer la vía AnnotationMethodHandlerAdapter primavera. Acabamos de prueba nuestras clases de controlador directamente.

¿Cómo puedo escribir una prueba de unidad o integración que fallará correctamente si mis anotaciones @MVC están equivocados? ¿Hay una manera que puedo pedir primavera de encontrar y ejercer el control pertinente con MockHttpServlet o algo?

¿Fue útil?

Solución

En la próxima primavera 3,2 (instantánea está disponible) o con la primavera-test-mvc (https://github.com/SpringSource/spring-test-mvc), puede hacerlo de esta manera:

primera emular Validación como no queremos poner a prueba el validador, sólo quiero saber si la validación se llama.

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");
        }
    }
}

esta es nuestra clase de prueba:

@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();
        }
    }
}

Otros consejos

pruebas de integración de escritura para este tipo de cosas. Digamos que tiene un grano con anotaciones de validación:

public class MyForm {
    @NotNull
    private Long myNumber;

    ...
}

y un controlador que se encarga de la presentación

@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";
    }
}

y que desea probar que las anotaciones @Valid y @NotNull están cableados correctamente:

@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"));        
    }

Ver mi blog el pruebas de integración de Spring MVC anotaciones

Claro. No hay ninguna razón por qué su prueba no puede crear una instancia de su propio DispatcherServlet, inyectarlo con los diversos temas que se tendría en un recipiente (por ejemplo ServletContext), incluyendo la ubicación del archivo de definición de contexto.

La primavera llega con una variedad de clases de servlet-MockXYZ relacionados para este propósito, incluyendo MockServletContext, MockHttpServletRequest y MockHttpServletResponse. Ellos no son realmente "simulacro" objetos en el sentido usual, son más como talones de tontos, pero hacen su trabajo.

contexto de prueba del servlet tendría los habituales relacionados con los granos de MVC, además de sus granos a prueba. Una vez que se inicializa el servlet, crear las peticiones y las respuestas simuladas, y darles de comer en el método de la service() Servet. Si la solicitud se enruta correctamente, puede comprobar los resultados según lo escrito a la respuesta simulada.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top