복붙노트

[SPRING] 봄 mockMvc 내 테스트에서 유효성 검사를 고려하지 않습니다.

SPRING

봄 mockMvc 내 테스트에서 유효성 검사를 고려하지 않습니다.

mockMvc와 통합 테스트를 설정하려고하는데, 문제가 있습니다. 실제로 스프링은 유효성 검사 주석을 통합하지 않습니다.  더 정밀도를 위해, 나는 테스트 할 수있는 Controller 클래스의 코드를 넣었다.

@Controller
public class UserRegisterController {
    private final Log log = LogFactory.getLog(UserRegisterController.class);

    private UserManager userManager;

    @Autowired
    public UserRegisterController(UserManager userManager){
        this.userManager = userManager;
    }

    /**
     * Register a new user.
     *
     */
    @RequestMapping(value = "/User/Register", 
            method = RequestMethod.GET
    )
    public @ResponseBody SimpleMessage submitForm(
            @Valid UserInfoNew userInfo,
            BindingResult result
    ){
        if(log.isInfoEnabled())
            log.info("Execute UserRegister action");
        SimpleMessage message;

        try {
            if(result.hasErrors()){
                if(log.isFatalEnabled())
                    log.fatal("Parameters sent by user for registering aren't conform. Errors are : "
                            + result.getFieldErrors().toString());
                throw new Exception(result.getFieldErrors().toString());
            }

            User user = new User();
            user.setLogin(userInfo.getLogin());
            user.setFamilyName(userInfo.getFamilyName());
            user.setFirstName(userInfo.getFirstName());
            user.setPassword(userInfo.getPassword());
            user.setDateBirthday(userInfo.getDateBirthday());
            user.setEmail(userInfo.getEmail());
            user.setMobile(userInfo.getMobile());
            user.setAddress(userInfo.getAddress());

            userManager.createUser(user);

            User newUser = userManager.findLastUserCreated();

            //Change to null some sensitive or useless return parameters
            newUser.setPassword(null);
            //

            message = new SimpleMessage(null, newUser);
        } catch (Exception e) {
            if(log.isErrorEnabled())
                log.error("A problem of type : " + e.getClass() 
                        + " has occured, with message : " + e.getMessage());
            message = new SimpleMessage(
                            new SimpleException(e.getClass(), e.getMessage()), null);
        }

        return message;
    }
}

그런 다음이 객체는 유효성 검사를 위해 hibernate와 javax annotation을 모두 포함합니다 :

public abstract class UserParameters {

    @Min(1)
    protected Long id;

    @Length(min=4, max=20)
    protected String login;

    @Length(min=4, max=20)
    protected String familyName;

    @Length(min=4, max=20)
    protected String firstName;

    @Pattern(regexp="^.*(?=.{8,20})(?=.*[a-z]+)(?=.*[a-z]+)(?=.*[A-Z]+)(?=.*[A-Z]+)"
            + "(?=.*[0-9]+)(?=.*[0-9]+)(?=.*[@$%*#]+).*$")
    protected String password;

    @Past
    protected Calendar dateBirthday;

    @Email
    @Length(max=255)
    protected String email;

    @Pattern(regexp="^[0]{1}[67]{1}[ .-]{1}[0-9]{2}[ .-]{1}"
            + "[0-9]{2}[ .-]{1}[0-9]{2}[ .-]{1}[0-9]{2}$")
    protected String mobile;

    @Length(max=255)
    protected String address;

    protected Calendar dateCreation;

    protected Calendar dateLastAccess;
}

public class UserInfoNew extends UserParameters  implements Serializable{   

    private static final long serialVersionUID = 4427131414801253777L;

    @NotBlank
    public String getLogin() {
            return login;
    }   
    public void setLogin(String Login) {
            this.login = Login;
    }

    public String getFamilyName() {
            return familyName;
    }   
    public void setFamilyName(String Name) {
            this.familyName = Name;
    }

    public String getFirstName() {
            return firstName;
    }   
    public void setFirstName(String FirstName) {
            this.firstName = FirstName;
    }

    @NotBlank
    public String getPassword() {
            return password;
    }   
    public void setPassword(String Password){
        this.password = Password;
    }

    public Calendar getDateBirthday() {
        return dateBirthday;
    }
    public void setDateBirthday(Calendar strBirthDay) {     
        this.dateBirthday = strBirthDay;
    }

    public String getEmail() {
        return email;
    }
    public void setEmail(String Mail) {
        this.email = Mail;
    }

    @NotBlank
    public String getMobile() {
        return mobile;
    }
    public void setMobile(String Mobile) {
        this.mobile = Mobile;
    }

    public String getAddress() {
        return address;
    }   
    public void setAddress(String Address) {
        this.address = Address;
    }
}

그리고 테스트를 실현하는 클래스 :

@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration(classes = {
        WebInit_Test.class,
        AppConfig_Test.class,
        WebConfig_1.class,
        WebConfig_2.class,
        WebSocketConfig.class
})
public class UserControllersTest {

    @Autowired
    private WebApplicationContext wac;

    private MockMvc mockMvc;

    @Before
    public void setUp() throws Exception {

        this.mockMvc = MockMvcBuilders.webAppContextSetup(wac)
                        .alwaysExpect(status().isOk())
                           .alwaysExpect(content().contentType("application/json;charset=UTF-8"))
                    .build();
}

@Test
public void userRegister() throws Exception {
    //doesn't consider @Valid during test
    mockMvc.perform(get("/User/Register?Login=A&Password=aaAA&Mobile=0134320285")
            .contentType(MediaType.ALL)
    )
            .andExpect(jsonPath("error").exists());


}
}

테스트를 시작할 때 오류 항목은 존재하지 않지만 로그인, 비밀번호 및 모바일은 javax 및 hibernate 주석으로 유효성을 검사 할 수 없습니다. 또한 localhost에 URL을 보내려고하면 유효성 검사가 작동하고 새 사용자가 데이터베이스에 저장되지 않습니다. 보시다시피, 내 웹 레이어에 대한 Java 코드 구성을 사용하여 문제가 발생한다고 가정합니다. 또한 저는 github (링크 : github.com/spring-projects/spring-mvc-showcase)의 스프링 팀에서 Mockmvc로 수행 할 수있는 모든 종류의 테스트에 대해 자세히 설명하는 프로젝트를 다운로드합니다. 유효성 검사 ( "org.springframework.samples.mvc.validation"패키지에서)는 프로젝트 구성에서는 작동하지 않지만 원본 구성에서는 매우 잘 작동합니다. 끝내려면 모든 구성 수업을 보내 드리겠습니다.

@Configuration
public class WebInit_Test extends AbstractAnnotationConfigDispatcherServletInitializer {

    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class<?>[] { AppConfig_Test.class };
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class<?>[] { WebConfig_1.class, WebConfig_2.class, WebSocketConfig.class };
    }

    @Override
    protected String[] getServletMappings() {
        return new String[] { "/" };
    }

    @Override
    protected void customizeRegistration(Dynamic registration) {
        registration.setInitParameter("dispatchOptionsRequest", "true");
        registration.setLoadOnStartup(1);
    }
}

@Configuration
@ImportResource({
    "classpath:/applicationContext-dao.xml",
    "classpath:/applicationContext-datasource-test.xml",
    "classpath:/applicationContext-service.xml"
})
public class AppConfig_Test {

}

@Configuration
@EnableWebMvc
@ComponentScan(
        basePackages = "project.web",
        excludeFilters = @ComponentScan.Filter(type= FilterType.ANNOTATION, value = Configuration.class)
)
public class WebConfig_1 extends WebMvcConfigurationSupport {

    @Autowired
    private FormattingConversionServiceFactoryBean conversionService;

    @Bean
    @Override
    public FormattingConversionService mvcConversionService() {
        FormattingConversionService conversionService = this.conversionService.getObject();
        addFormatters(conversionService);
        return conversionService;
    }
}

@Configuration
public class WebConfig_2 extends WebMvcConfigurerAdapter{

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

    /**
     * Configure output mapping, see 
     * {@link http://stackoverflow.com/questions/4823358/spring-configure-responsebody-json-format} 
     * for more information
     * 
     * @param converters
     *          a list of {@link HttpMessageConverter<?>}
     */
    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        final MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
        final ObjectMapper objectMapper = new ObjectMapper();        
        objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
        converter.setObjectMapper(objectMapper);
        converters.add(converter);
        super.configureMessageConverters(converters);
    }
}

@Configuration
//@EnableScheduling
@ComponentScan(
        basePackages="project.web",
        excludeFilters = @ComponentScan.Filter(type= FilterType.ANNOTATION, value = Configuration.class)
)
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {

    @Override
    public void configureMessageBroker(MessageBrokerRegistry config) {
        config.enableSimpleBroker("/friendship", "/message", "/journey", "/information");
        config.setApplicationDestinationPrefixes("/app");
    }

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/client").withSockJS();
    }
}

당신의 도움을 주셔서 감사합니다.

해결법

  1. ==============================

    1.유효성 검사기를 5.1.0. 최종으로 업데이트 한 후에도 동일한 문제가 발생합니다. 응용 프로그램은 완벽하게 작동하지만 REST는 테스트하지 않습니다 (@Valid 주석은 전혀 고려되지 않습니다). 필자는 테스트에만 하나의 추가 종속성을 추가하여이 문제를 해결했습니다.

    유효성 검사기를 5.1.0. 최종으로 업데이트 한 후에도 동일한 문제가 발생합니다. 응용 프로그램은 완벽하게 작동하지만 REST는 테스트하지 않습니다 (@Valid 주석은 전혀 고려되지 않습니다). 필자는 테스트에만 하나의 추가 종속성을 추가하여이 문제를 해결했습니다.

       <dependency>
         <groupId>javax.el</groupId>
         <artifactId>javax.el-api</artifactId>
         <version>2.2.4</version>
         <scope>test</scope>
      </dependency>
    
  2. ==============================

    2.당신이 최대 절전 모드 버전 5.4.1을 사용하고 있다면. 최종 테스트를 위해 의존성을 추가하십시오.

    당신이 최대 절전 모드 버전 5.4.1을 사용하고 있다면. 최종 테스트를 위해 의존성을 추가하십시오.

    <dependency>
        <groupId>org.glassfish</groupId>
        <artifactId>javax.el</artifactId>
        <version>3.0.0</version>
    </dependency>
    

    이 종속성은 "제공된"종속성입니다. 메이븐 사이트에서 최대 절전 모드 버젼과 일치하는 의존성을 찾을 수 있습니다. https://mvnrepository.com/artifact/org.hibernate/hibernate-validator/5.4.1. 최종

    예를 들어 5.4.1 버전을 사용하고 있다면 위의 링크로 이동하여 제공된 종속성을 확인하고 사용하십시오.

  3. ==============================

    3.좋습니다, 저는 방금 검증이 mockmvc에 의해 고려되지 않았다는 사실에 책임이있는 것을 발견했습니다. 그것은 단지 pom의 나쁜 의존성입니다.  나는 사용했다.

    좋습니다, 저는 방금 검증이 mockmvc에 의해 고려되지 않았다는 사실에 책임이있는 것을 발견했습니다. 그것은 단지 pom의 나쁜 의존성입니다.  나는 사용했다.

    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-validator</artifactId>
        <version>5.1.0.Final</version>
    </dependency>
    

    그리고 내가 그것을

    <dependency>
        <groupId>javax.validation</groupId>
        <artifactId>validation-api</artifactId>
        <version>1.0.0.GA</version>
    </dependency>
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-validator</artifactId>
        <version>4.1.0.Final</version>
    </dependency>
    

    테스트는 잘 작동합니다! 문제가 해결되었지만이 부분에서 문제가 발생하는 이유가 궁금합니다. hibernate-validator 5.1.0.Final은 전이 의존성 (transitive dependency)에서 javax 유효성 검사를 포함하므로 일반적으로이 문제는 발생하지 않습니다.

  4. from https://stackoverflow.com/questions/24049480/spring-mockmvc-doesnt-consider-validation-in-my-test by cc-by-sa and MIT license