programing

스프링 MVC 컨트롤러 유닛테스트가 @ControllerAdvice를 호출하지 않음

iphone6s 2023. 3. 18. 08:22
반응형

스프링 MVC 컨트롤러 유닛테스트가 @ControllerAdvice를 호출하지 않음

이는 「컨트롤러」라고 코멘트가 붙어 있습니다.@ControllerAdvice각 컨트롤러에서 사용되는 특정 데이터 요소를 설정합니다.하고 Spring MVC 3.2Junits를 이 컨트롤러에 사용합니다.하면 컨트롤이 Junit으로 .ControllerAdviceTomcat이치노

아무 생각 없어요?

@to의 답변과 다른 유사한 답변을 사용한 후 제한을 발견하여 https://jira.spring.io/browse/SPR-12751에서 문제를 제기하였습니다.

을 등록할 수 기능이 도입되었습니다.@ControllerAdvice4.2의 빌더에 있는 클래스입니다.스프링 부트를 사용하고 있는 경우는, 1.3.0 이후가 필요합니다.

하는 경우 을 할 수 .ControllerAdvice다음과 같이 합니다.

mockMvc = MockMvcBuilders.standaloneSetup(yourController)
            .setControllerAdvice(new YourControllerAdvice())
            .build();

주의: 이름setControllerAdvice()에는 var-instature 시그니처가 포함되어 있기 때문에 즉시 명확하게 할 수는 없지만 많은 인스턴스를 전달할 수 있습니다.

클래스 MyControllerAdvice에 @ControllerAdvice에 주석이 달렸고 @ExceptionHandler에 주석이 달린 메서드가 있다고 가정합니다.MockMvc의 경우 이 클래스를 예외 해결사로 쉽게 추가할 수 있습니다.

@Before
public void beforeTest() {
    MockMvc mockMvc = standaloneSetup(myControllers)
        .setHandlerExceptionResolvers(createExceptionResolver())
        .build();
}

private ExceptionHandlerExceptionResolver createExceptionResolver() {
    ExceptionHandlerExceptionResolver exceptionResolver = new ExceptionHandlerExceptionResolver() {
        protected ServletInvocableHandlerMethod getExceptionHandlerMethod(HandlerMethod handlerMethod, Exception exception) {
            Method method = new ExceptionHandlerMethodResolver(MyControllerAdvice.class).resolveMethod(exception);
            return new ServletInvocableHandlerMethod(new MyControllerAdvice(), method);
        }
    };
    exceptionResolver.afterPropertiesSet();
    return exceptionResolver;
}

할 때도 요.ExceptionHandler'어느 정도'라는 주석이 붙어 .@ControllerAdvice에는 '아예'를 @Configuration@EnableWebMvc을 붙일 수 있습니다.@ContextConfiguration시험 수업 중에

그래서 제 테스트는 이렇습니다.

@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration(classes = {
  RestProcessingExceptionHandler.class,
  TestConfiguration.class,
  RestProcessingExceptionThrowingController.class })
public class TestRestProcessingExceptionHandler {

  private MockMvc mockMvc;
  @Autowired
  WebApplicationContext wac;

  @Before
  public void setup() {
    mockMvc = webAppContextSetup(wac).build();
  }

  @Configuration
  // !!! this is very important - conf with this annotation 
  //     must be included in @ContextConfiguration
  @EnableWebMvc
  public static class TestConfiguration { }

  @Controller
  @RequestMapping("/tests")
  public static class RestProcessingExceptionThrowingController {
    @RequestMapping(value = "/exception", method = GET)
    public @ResponseBody String find() {
      throw new RestProcessingException("global_error_test");
    }
  }

  @Test
  public void testHandleException() throws Exception {
    mockMvc.perform(get("/tests/exception"))
      .andExpect(new ResultMatcher() {
        @Override
        public void match(MvcResult result) throws Exception {
          result.getResponse().getContentAsString().contains("global_error_test");
        }
      })
      .andExpect(status().isBadRequest());
  }
}

★★★★★★★★★★★★★★★★ @EnableWebMvc이치노

이 코드는 유효합니다.

public class MyGlobalExceptionHandlerTest {

    private MockMvc mockMvc;

    @Mock
    HealthController healthController;

    @BeforeTest
    public void setUp() {
        MockitoAnnotations.initMocks(this);
        mockMvc = MockMvcBuilders.standaloneSetup(healthController)
            .setControllerAdvice(new GlobalExceptionHandler())
            .build();
    }

    @Test(groups = { "services" })
    public void testGlobalExceptionHandlerError() throws Exception {
        Mockito.when(healthController.health())]
               .thenThrow(new RuntimeException("Unexpected Exception"));
        mockMvc.perform(get("/health")).andExpect(status().is(500));
    }
}

나는 꽤 오랫동안 같은 일로 고생해 왔다.자세히 살펴본 결과, 가장 좋은 참고 자료는 Spring 문서였습니다.

http://static.springsource.org/spring/docs/3.2.x/spring-framework-reference/html/testing.html#spring-mvc-test-framework

즉, 컨트롤러와 그 메서드를 단순히 테스트하는 경우에는 간단한 Spring MVC 설정을 작성하는 'standalone Setup' 방식을 사용할 수 있습니다.여기에는 @ControllerAdvice로 주석을 다는 오류 핸들러는 포함되지 않습니다.

private MockMvc mockMvc;

@Before
public void setup() {
    this.mockMvc = MockMvcBuilders.standaloneSetup(new AccountController()).build();
}

// ...

에러 핸들러를 포함한 보다 완전한 Spring MVC 설정을 작성하려면 , 다음의 설정을 사용할 필요가 있습니다.

@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration("test-servlet-context.xml")
public class AccountTests {

    @Autowired
    private WebApplicationContext wac;

    private MockMvc mockMvc;

    @Autowired
    private AccountService accountService;

    // ...

}

ControllerAdvice 한다@WebMvcTestSpring-Doc Works도 참조해 주세요.

예:

@RunWith(SpringRunner.class)
@WebMvcTest(ProductViewController.class)

@sampleuski 샘플 코드는 동작하지만, 동작의 구조를 이해하는 것은 유익합니다.이것은 설정 방법 중 하나일 뿐입니다.

@EnableWebMvc.

<mvc:annotation-driven />

기본적으로는 Spring MVC를 초기화하고 모든 컨트롤러와 빈 레퍼런스를 로드해야 합니다.따라서 다음 설정은 유효한 설정일 뿐만 아니라 대체 설정일 수도 있습니다.

테스트 클래스를 설정하는 방법은 다음과 같습니다.

    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(locations = { "classpath: "classpath:test-context.xml" })
    @WebAppConfiguration    
    public class BaseTest {

        @Autowired
        WebApplicationContext wac;

        private MockMvc mockMvc;

        @Before
        public void setUp()  {
            mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
        }
    }

테스트용 스프링 구성은 다음과 같습니다.

<mvc:annotation-driven />
<context:component-scan base-package="com.base.package.controllers" />

이 문제는 spark(groovy)로 컨트롤러 테스트를 작성하는 중에 발생했습니다.저의 시험 수업은 원래 다음과 같이 작성되었습니다.

@AutoConfigureMockMvc(secure = false)
@SpringBootTest
@Category(RestTest)
class FooControllerTest extends Specification {
  def fooService = Mock(FooService)
  def underTest = new FooController(FooService)
  def mockMvc = MockMvcBuilders.standaloneSetup(underTest).build()
....
}

이로 인해 ControllerAdvice는 무시되었습니다.코드를 [Autowire](자동 배선)으로 변경하면 문제가 해결.

@AutoConfigureMockMvc(secure = false)
@SpringBootTest
@Category(RestTest)
class FooControllerTest extends Specification {

  @AutowiredMock
  FooService FooService

  @Autowired
  MockMvc mockMvc

구체적인 답변을 예상하기 전에 추가 정보 및 실제 코드 및/또는 구성 파일을 제공해야 합니다.단, 당신이 제공한 소량으로 볼 때 주석이 달린 콩이 로딩되지 않은 것 같습니다.

다음 항목을 테스트 applicationContext.xml(또는 동등한 스프링 설정 파일(사용하는 경우))에 추가해 보십시오.

<context:component-scan base-package="com.example.path.to.package" />

또는 테스트 클래스 전에 다음 주석을 포함하여 테스트 내에 콘텍스트를 '수동으로' 로드해야 할 수도 있습니다.

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("/applicationContext.xml")

행운을 빕니다.

테스트에서 asyncDispatch를 사용해야 할 것 같습니다.일반 테스트 프레임워크는 비동기 컨트롤러로 망가져 있습니다.

다음 URL에서 접근 방법을 사용해 보십시오.https://github.com/spring-projects/spring-framework/blob/master/spring-test/src/test/java/org/springframework/test/web/servlet/samples/standalone/AsyncTests.java

가장 간단한 방법은 @ControllerAdvice 주석 클래스를 @ContextConfiguration에 추가하는 것입니다.

나는 이것으로부터 변해야 했다.

@AutoConfigureMockMvc
@ContextConfiguration(classes = OrderController.class)
@WebMvcTest
class OrdersIntegrationTest

다음과 같이 입력합니다.

@AutoConfigureMockMvc
@ContextConfiguration(classes = {OrderController.class, OrdersExceptionHandler.class})
@WebMvcTest
class OrdersIntegrationTest

Spring Boot 2.x를 사용하고 있습니다만, MockMvcBuilders가 필요 없게 되었거나 ControllerAdvice를 Configuration의 일부로 정의하고 있기 때문에 로드됩니다.

@WebMvcTest
@ContextConfiguration(classes = {
  UserEndpoint.class, //the controller class for test
  WebConfiguration.class, //security configurations, if any
  StandardRestExceptionInterpreter.class. //<-- this is the ControllerAdvice class
})
@WithMockUser(username = "test@asdf.com", authorities = {"DEFAULT"})
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class UserEndpointTests {

@Test
@Order(3)
public void shouldThrowExceptionWhenRegisteringDuplicateUser() throws Exception {
    //do setup...
    Mockito.doThrow(EntityExistsException.class).when(this.userService).register(user);

    this.mockMvc
            .perform(MockMvcRequestBuilders
                    .post("/users")
                    .contentType(MediaType.APPLICATION_JSON)
                    .content(this.objectMapper.writeValueAsString(user)))
            .andDo(MockMvcResultHandlers.print())
            .andExpect(MockMvcResultMatchers.status().isConflict());
    }
}

@WebMvcTest를 특정 컨트롤러와 함께 사용하는 경우 컨트롤러 어드바이저는 스프링 구성(https://github.com/spring-projects/spring-boot/issues/12979에서 사용되지 않습니다.

@Import 주석을 통해 스프링에 컨트롤러 조언을 사용하도록 명시적으로 지시할 수 있습니다.

@WebMvcTest(controllers = AppController.class)
@Import(AppControllerAdvice.class)
class AppControllerTest {

    @Autowired
    private MockMvc mockMvc;
}

같은 문제가 있었는데 @Spring Boot 클래스에 어드바이저를 추가하여 해결했습니다.테스트:

@RunWith(SpringRunner.class)
@SpringBootTest(classes = {MyController.class, MyControllerAdvice.class})
@AutoConfigureMockMvc(secure = false)
@ContextConfiguration(classes = {MyTestConfig.class})
@EnableWebMvc

언급URL : https://stackoverflow.com/questions/15302243/spring-mvc-controllers-unit-test-not-calling-controlleradvice

반응형