Spring Контроллеры MVC Unit Test, не вызывающие @ControllerAdvice
У меня есть набор контроллеров в приложении и класс, аннотированный как @ControllerAdvice
, который устанавливает определенные элементы данных, которые используются в каждом из этих контроллеров. Я использую Spring MVC 3.2
и имею Junits для этих контроллеров. Когда я запускаю Junit, элемент управления не идет в класс ControllerAdvice
, если он работает отлично, если я развертываю приложение в Tomcat
и отправляю запрос через браузер.
Любые мысли, пожалуйста?
Ответы
Ответ 1
После использования ответа от @eugene-to и другого подобного здесь я нашел ограничения и поднял проблему на Spring: https://jira.spring.io/browse/SPR-12751
В результате тест Spring ввел возможность зарегистрировать классы @ControllerAdvice
в построителе в 4.2. Если вы используете Spring Boot, вам понадобится 1.3.0 или новее.
При этом улучшении, если вы используете автономную настройку, вы можете установить один или несколько экземпляров ControllerAdvice
, например:
mockMvc = MockMvcBuilders.standaloneSetup(yourController)
.setControllerAdvice(new YourControllerAdvice())
.build();
Примечание. имя setControllerAdvice()
может не сделать это сразу же очевидным, но вы можете передать ему много экземпляров, поскольку оно имеет подпись var-args.
Ответ 2
Предположим, что у вас есть класс 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;
}
Ответ 3
У меня была аналогичная проблема при попытке протестировать 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
мой тест прошел.
Ответ 4
Я боролся с тем же самым в течение достаточно долгого времени. После долгих поисков лучшим справочником была документация Spring:
http://static.springsource.org/spring/docs/3.2.x/spring-framework-reference/html/testing.html#spring-mvc-test-framework
Короче говоря, если вы просто тестируете контроллер и его методы, вы можете использовать метод standaloneSetup, который создает простую конфигурацию Spring MVC. Это не будет включать ваш обработчик ошибок, который вы аннотируете с помощью @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;
// ...
}
Ответ 5
Это работает для меня
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)).andReturn();
}
}
Ответ 6
@tunguski пример кода работает, но он платит, чтобы понять, как все работает. Это всего лишь один способ установить ситуацию.
@EnableWebMvc
эквивалентен следующему в конфигурационном файле spring
<mvc:annotation-driven />
По сути, для работы вам необходимо инициализировать spring Mvc и загрузить все ваши контроллеры и ссылки bean. Таким образом, следующая допустимая установка, а также альтернативный
Ниже описано, как настроить тестовый класс
@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();
}
}
И следующая конфигурация spring для теста
<mvc:annotation-driven />
<context:component-scan base-package="com.base.package.controllers" />
Ответ 7
Вам нужно будет предоставить дополнительную информацию и, возможно, некоторые фактические файлы кода и/или конфигурации, прежде чем вы сможете ожидать конкретных ответов. При этом, основываясь на том, что вы предоставили, похоже, что аннотированный bean не загружается.
Попробуйте добавить в тестовый файл applicationContext.xml(или эквивалентный файл конфигурации spring), если вы используете его.
<context:component-scan base-package="com.example.path.to.package" />
В качестве альтернативы вам может потребоваться "вручную" загрузить контексты в тестах, включив следующие аннотации перед вашим тестовым классом:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("/applicationContext.xml")
Удачи!
Ответ 8
Я столкнулся с этой проблемой при написании тестов контроллера с помощью spock (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 mocks устраняет проблему.
@AutoConfigureMockMvc(secure = false)
@SpringBootTest
@Category(RestTest)
class FooControllerTest extends Specification {
@AutowiredMock
FooService FooService
@Autowired
MockMvc mockMvc
Ответ 9
Я подозреваю, что вам нужно использовать asyncDispatch в вашем тесте; среда обычного тестирования нарушена асинхронными контроллерами.
Попробуйте подход в: https://github.com/spring-projects/spring-framework/blob/master/spring-test/src/test/java/org/springframework/test/web/servlet/samples/standalone/AsyncTests.Джава