복붙노트

[SPRING] Spring MockMVC - 컨트롤러 외부에서 실행되는 커스텀 유효성 검사기를 조롱하는 법

SPRING

Spring MockMVC - 컨트롤러 외부에서 실행되는 커스텀 유효성 검사기를 조롱하는 법

@UsernameAlreadyExists
private String username;

계정 작성 양식을 제출할 때 중복 된 사용자 이름이 응용 프로그램에 의해 잡히도록하기 위해 만든 사용자 정의 유효성 검사기가 있습니다.

MockMVC를 사용하여 계정 생성 컨트롤러를 테스트 할 때 유효성 검사기가 서비스에 의존하기 때문에 실패합니다. 따라서 널 포인터 예외가 발생합니다.

이 유효성 검사기가 의존하는 유효성 검사기 또는 서비스를 조롱하려면 어떻게해야합니까? 컨트롤러가 명시 적으로 유효성 검사기에 의존하지 않고 컨트롤러 외부에서 실행되므로이 ​​작업을 수행하는 방법을 알 수 없습니다.

해결법

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

    1.ConstraintValidator를 조롱 할 수는 없지만, 예를 들어 콩을 조롱하는 일반적인 스프링 방법을 사용하여 유효성 검사기가 의존하는 서비스를 조롱 할 수 있습니다.

    ConstraintValidator를 조롱 할 수는 없지만, 예를 들어 콩을 조롱하는 일반적인 스프링 방법을 사용하여 유효성 검사기가 의존하는 서비스를 조롱 할 수 있습니다.

    .1. 잠재적으로 동일한 bean 이름을 가진 mock 인스턴스를 정의하여 모의 인스턴스가 실제 인스턴스 다음에로드되도록합니다.

    .2. mock bean 만 정의 된 테스트 구성으로 테스트하십시오.

  2. ==============================

    2.전체 Spring 컨텍스트를로드하지 않고 'standaloneSetup'을 사용하여 테스트 할 때 유효성 검사는 SpringWebConstraintValidatorFactory의 프레임 워크 호출에 의해 내부적으로 트리거됩니다. 해당 흐름에 연결하려면 'mockMvc'에 SpringWebConstraintValidatorFactory의 새 인스턴스를 설정해야합니다. 불행히도 그렇게 쉬운 방법은 쉽지 않습니다. SpringWebConstraintValidatorFactory를 서브 클래스 화하고 mockMvc에서 차례대로 설정할 수있는 LocalValidatorFactoryBean에 인스턴스를 설정해야한다. 그러나 LocalValidatorFactoryBean은 ApplicationContext를 필요로합니다. 다음은 그 예입니다.

    전체 Spring 컨텍스트를로드하지 않고 'standaloneSetup'을 사용하여 테스트 할 때 유효성 검사는 SpringWebConstraintValidatorFactory의 프레임 워크 호출에 의해 내부적으로 트리거됩니다. 해당 흐름에 연결하려면 'mockMvc'에 SpringWebConstraintValidatorFactory의 새 인스턴스를 설정해야합니다. 불행히도 그렇게 쉬운 방법은 쉽지 않습니다. SpringWebConstraintValidatorFactory를 서브 클래스 화하고 mockMvc에서 차례대로 설정할 수있는 LocalValidatorFactoryBean에 인스턴스를 설정해야한다. 그러나 LocalValidatorFactoryBean은 ApplicationContext를 필요로합니다. 다음은 그 예입니다.

    
    
        public class TestConstrainValidationFactory extends SpringWebConstraintValidatorFactory {
    
            private final WebApplicationContext ctx;
    
            private boolean isValid = false;
    
            public TestConstrainValidationFactory(WebApplicationContext ctx) {
                this.ctx = ctx;
            }
    
            @Override
            public < T extends ConstraintValidator<?, ?>> T getInstance(Class key) {
                ConstraintValidator instance = super.getInstance(key);
                if (instance instanceof DeviceValidator) {
                    DeviceValidator deviceValidator = (DeviceValidator) instance;
                    deviceValidator.setYourAutowiredField((String id, String type) -> isValid); //change that to suit your needs
                    instance = deviceValidator;
                }
                return (T) instance;
            }
    
            @Override
            protected WebApplicationContext getWebApplicationContext() {
                return ctx;
            }
    
        }
    
    

    그것을 mockMvc에 연결하는 예제

    
    
        @RunWith(SpringJUnit4ClassRunner.class)
        @SpringApplicationConfiguration(classes = MockServletContext.class)
        @WebAppConfiguration()
        public class DevicesControllerTest {
            @Autowired
            private MockServletContext servletContext;
            @InjectMocks
            private DevicesController devicesController;
            private TestConstrainValidationFactory constraintFactory;
    
            @Before
            public void setUp() {
                MockitoAnnotations.initMocks(this);
    
                final GenericWebApplicationContext context = new GenericWebApplicationContext(servletContext);
                final ConfigurableListableBeanFactory beanFactory = ((ConfigurableApplicationContext) context).getBeanFactory();
                beanFactory.registerSingleton(DeviceValidator.class.getCanonicalName(), new DeviceValidator());
                context.refresh();
    
                LocalValidatorFactoryBean validatorFactoryBean = new LocalValidatorFactoryBean();
                validatorFactoryBean.setApplicationContext(context);
                constraintFactory = new TestConstrainValidationFactory(context);
                validatorFactoryBean.setConstraintValidatorFactory(constraintFactory);
                validatorFactoryBean.setProviderClass(HibernateValidator.class);
                validatorFactoryBean.afterPropertiesSet();
    
                this.mockMvc = MockMvcBuilders
                        .standaloneSetup(devicesController)
                        .setValidator(validatorFactoryBean)
                        .setHandlerExceptionResolvers()
                        .build();
            }
        }
    
    

    일단 당신이 그것을 가지고, ReflectionTestUtils.setField (constraintFactory, "isValid", 거짓); 예상대로 작동하고 공장을 통해 검사기에서 필드를 설정할 수 있습니다. 문제 상황보기 spring-projects / spring-test-mvc / issues :

  3. from https://stackoverflow.com/questions/23161752/spring-mockmvc-how-to-mock-custom-validators-running-outside-of-controllers by cc-by-sa and MIT license