Тест WebMvc с ControllerAdvice, который содержит свойства автопроводки - PullRequest
0 голосов
/ 15 мая 2018

Учитывая приведенный ниже код как часть приложения SpringBoot с последними версиями, в некоторых проектах результатом теста является сбой при запуске приложения, поскольку ему не удалось внедрить ErrorMessages в ControllerAdvice. Но почему-то в других проектах этот код проходит. У меня нет никаких различий в конфигурации, сборке или аннотациях, поэтому я не совсем уверен, нашел ли я ошибку или нет. Есть ли способ повлиять на сообщения ErrorMessages, которые будут прочитаны и введены в @WebMvcTest?

Контроллер в папке контроллера

@RestController
@Api(value = "Some Service", tags = "Some Service")
public class SomeController {

    @Autowired
    SomeService someService;

    @ApiOperation(value = "Gets something")
    @ApiResponses(value = {
            @ApiResponse(code = 200, message = "OK"),
            @ApiResponse(code = 500, message = "Internal server error", response = ErrorResponse.class) })
    @GetMapping(value = "/something", produces = MediaType.APPLICATION_JSON_VALUE)
    public ResponseEntity<SomeResponse> getSomething(
            @AuthenticationPrincipal CustomOAuth2Authentication authentication,
    ) throws ApiException {
        return ResponseEntity.ok(someService.get());
    }
}

Совет контроллера по папке исключений

@Order(Ordered.HIGHEST_PRECEDENCE)
@ControllerAdvice
public class GlobalExceptionHandler {

    @Autowired
    private ErrorMessages errorMessages;

    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    @ExceptionHandler(Throwable.class)
    @ResponseBody
    public ErrorResponse handler(HttpServletRequest request, final Throwable ex) 
    {
        log.error("Unexpected error", ex);
        return new ErrorResponseBuilder().with(it -> {
            it.status = ErrorCodes.INTERNAL_SERVER_EXCEPTION;
            it.error = ex.getLocalizedMessage();
            it.exception = ex.getClass().getName();
            it.messages = Collections.singletonList(errorMessages.internalServerException);
            it.path = request.getRequestURI();
        }).build();
    }
}

errorMessages в папке исключений (читает из Spring Cloud)

@Component
public class ErrorMessages {

    @Value("${"+ErrorCodes.INTERNAL_SERVER_EXCEPTION +"}")
    public String internalServerException;

}

коды ошибок в папке исключений

public class ErrorCodes {
    private ErrorCodes() {}

    public static final String INTERNAL_SERVER_EXCEPTION = "3031";
}

TestClass в папке Test

@RunWith(SpringRunner.class)
@WebMvcTest(controllers = SomeController.class)
@ActiveProfiles("test")
@ContextConfiguration(classes = {ErrorMessages.class, 
GlobalExceptionHandler.class})
public class SomeControllerTest {

    private String SERVICE_URL = "/some";

    @Autowired
    private MockMvc mockMvc;

    @Autowired
    private WebApplicationContext wac;

    @Before
    public void setup() throws ApiException {

        this.mockMvc = MockMvcBuilders
                .webAppContextSetup(this.wac)
                .apply(SecurityMockMvcConfigurers.springSecurity())
                .build();
    }

    @Autowired
    ErrorMessages errorMessages;

    @MockBean
    private SomeService someService;

    @Autowired
    @InjectMocks
    private SomeController someController;

    @Test
    @WithMockCustomUser()
    public void getCheckout_Exception() throws Exception {
        ApiException e = new ApiException("code123", "message123");
        when(someService.get(anyString(), anyInt())).thenThrow(e);
        mockMvc.perform(get(SERVICE_URL))
            .andExpect( status().is( equalTo( 
               HttpStatus.INTERNAL_SERVER_ERROR.value())))
            .andExpect( content().string(containsString(e.getClass().getName())))
            .andExpect( content().string(containsString(e.getCode())))
            .andExpect( content().string(containsString(e.getMessage())))
            .andExpect( content().string(containsString(errorMessages.transformingException)));
    }
}

Ошибка

java.lang.IllegalStateException: Failed to load ApplicationContext

at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:125)
at org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java:108)
at org.springframework.boot.test.mock.mockito.MockitoTestExecutionListener.postProcessFields(MockitoTestExecutionListener.java:99)
at org.springframework.boot.test.mock.mockito.MockitoTestExecutionListener.injectFields(MockitoTestExecutionListener.java:79)
at org.springframework.boot.test.mock.mockito.MockitoTestExecutionListener.prepareTestInstance(MockitoTestExecutionListener.java:54)
at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:246)

Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'globalExceptionHandler': Unsatisfied dependency expressed through field 'errorMessages'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.comp.proj.service.something.exception.ErrorMessages' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:587)
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:91)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:373)
...