복붙노트

[SPRING] JUnitTest의 @ControllerAdvice 주석이 달린 컨트롤러를 MockMVC에 등록하십시오.

SPRING

JUnitTest의 @ControllerAdvice 주석이 달린 컨트롤러를 MockMVC에 등록하십시오.

내 @ControllerAdvice 주석이 달린 컨트롤러는 다음과 같습니다.

@ControllerAdvice
public class GlobalControllerExceptionHandler {

    @ResponseStatus(value = HttpStatus.UNAUTHORIZED)
    @ExceptionHandler(AuthenticationException.class)
    public void authenticationExceptionHandler() {
    }
}

물론 내 개발은 테스트 중심이며 JUnit 테스트에서 예외 처리기를 사용하고 싶습니다. 내 테스트 케이스는 다음과 같습니다.

public class ClientQueriesControllerTest {

    private MockMvc mockMvc;

    @InjectMocks
    private ClientQueriesController controller;

    @Mock
    private AuthenticationService authenticationService;

    @Before
    public void setup() {
        MockitoAnnotations.initMocks(this);
        mockMvc = MockMvcBuilders.standaloneSetup(controller).build();
    }

    @Test
    public void findAllAccountRelatedClientsUnauthorized() throws Exception {
        when(authenticationService.validateAuthorization(anyString())).thenThrow(AuthenticationException.class);

        mockMvc.perform(get("/rest/clients").header("Authorization", UUID.randomUUID().toString()))
                .andExpect(status().isUnauthorized());
    }
}

아마도 ControllerAdvice 클래스를 등록해야합니다. 그렇게하는 방법?

해결법

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

    1.Spring 4.2부터 ControllerAdvice를 직접 StandaloneMockMvcBuilder에 등록 할 수 있습니다 :

    Spring 4.2부터 ControllerAdvice를 직접 StandaloneMockMvcBuilder에 등록 할 수 있습니다 :

    MockMvcBuilders
         .standaloneSetup(myController)
         .setControllerAdvice(new MyontrollerAdvice())
         .build();
    
  2. ==============================

    2.전체 Spring MVC 설정을 활성화하려면 MockMvcBuilders.standaloneSetup 대신 MockMvcBuilders.webAppContextSetup을 사용해야합니다.

    전체 Spring MVC 설정을 활성화하려면 MockMvcBuilders.standaloneSetup 대신 MockMvcBuilders.webAppContextSetup을 사용해야합니다.

    자세한 것은 Spring 문서의이 부분을 확인하십시오.

    코드는 다음과 같습니다.

    @RunWith(SpringJUnit4ClassRunner.class)
    @WebAppConfiguration
    @ContextConfiguration("test-config.xml")
    public class ClientQueriesControllerTest {
    
        private MockMvc mockMvc;
    
        @Autowired
        private WebApplicationContext webApplicationContext;
    
        @Autowired
        private AuthenticationService authenticationService;
    
        @Before
        public void setup() {
            MockitoAnnotations.initMocks(this);
            mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
        }
    
        @Test
        public void findAllAccountRelatedClientsUnauthorized() throws Exception {
            when(authenticationService.validateAuthorization(anyString())).thenThrow(AuthenticationException.class);
    
            mockMvc.perform(get("/rest/clients").header("Authorization", UUID.randomUUID().toString()))
                    .andExpect(status().isUnauthorized());
        }
    }
    

    그런 다음 test-config.xml 내에서 모의 ​​인 AuthenticationService 용 Spring bean을 추가한다.

    <bean id="authenticationService" class="org.mockito.Mockito" factory-method="mock">
        <constructor-arg value="your.package.structure.AuthenticationService"/>
    </bean>
    

    test-config.xml을 만드는 대신 일반 Spring 구성 파일을 다시 사용하려면 모의 AuthenticationService를 테스트에 삽입하는 데 프로필을 사용할 수 있습니다.

    최신 정보

    조금 뒤져서, (MockMvcBuilders.standaloneSetup)에 의해 반환 된 StandaloneMockMvcBuilder가 완전히 사용자 정의 가능하다는 것을 알았습니다. 즉, 사용자가 선호하는 예외 해석자를 플러그인 할 수 있습니다.

    그러나 @ControllerAdvice를 사용하고 있기 때문에 아래 코드는 작동하지 않습니다. 그러나 @ExceptionHandler 메서드가 동일한 컨트롤러 안에 있으면 코드를 모두 변경해야합니다.

    mockMvc = MockMvcBuilders.standaloneSetup(controller).setHandlerExceptionResolvers(new ExceptionHandlerExceptionResolver()).build();
    

    업데이트 2

    @ControllerAdvice를 사용할 때 정확한 예외 핸들러를 등록 할 수있는 방법에 대한 답을 얻습니다.

    테스트의 설정 코드를 다음과 같이 업데이트해야합니다.

        @Before
        public void setUp() throws Exception {
            final ExceptionHandlerExceptionResolver exceptionHandlerExceptionResolver = new ExceptionHandlerExceptionResolver();
    
            //here we need to setup a dummy application context that only registers the GlobalControllerExceptionHandler
            final StaticApplicationContext applicationContext = new StaticApplicationContext();
            applicationContext.registerBeanDefinition("advice", new RootBeanDefinition(GlobalControllerExceptionHandler.class, null, null));
    
            //set the application context of the resolver to the dummy application context we just created
            exceptionHandlerExceptionResolver.setApplicationContext(applicationContext);
    
            //needed in order to force the exception resolver to update it's internal caches
            exceptionHandlerExceptionResolver.afterPropertiesSet();
    
            mockMvc = MockMvcBuilders.standaloneSetup(controller).setHandlerExceptionResolvers(exceptionHandlerExceptionResolver).build();
        }
    
  3. ==============================

    3.다음 해결책으로 NestedServletException을 지나쳤습니다 ...

    다음 해결책으로 NestedServletException을 지나쳤습니다 ...

        final StaticApplicationContext applicationContext = new StaticApplicationContext();
        applicationContext.registerSingleton("exceptionHandler", GlobalControllerExceptionHandler.class);
    
        final WebMvcConfigurationSupport webMvcConfigurationSupport = new WebMvcConfigurationSupport();
        webMvcConfigurationSupport.setApplicationContext(applicationContext);
    
        mockMvc = MockMvcBuilders.standaloneSetup(controller).
            setHandlerExceptionResolvers(webMvcConfigurationSupport.handlerExceptionResolver()).
            build();
    
  4. ==============================

    4.이것을 테스트 클래스에 추가 할 수 있습니다.

    이것을 테스트 클래스에 추가 할 수 있습니다.

    @Autowired
    @Qualifier("handlerExceptionResolver")
    void setExceptionResolver(HandlerExceptionResolver resolver)
    {
        this.exceptionResolver = resolver;
    }
    

    MockMvc에 exceptionResolver를 추가하십시오.

    @Before
    public void setup() {
        MockitoAnnotations.initMocks(this);
        mockMvc = MockMvcBuilders.standaloneSetup(controller)
                   .setHandlerExceptionResolvers(this.exceptionResolver).build();
    }
    
  5. from https://stackoverflow.com/questions/25604215/register-controlleradvice-annotated-controller-in-junittest-with-mockmvc by cc-by-sa and MIT license