How to test existing camel endpoints with mock? - spring-boot

Im currently working with Camel's mock component and i would like to test it on an existing routes. Basically i want to retain the existing routes defined in the app, but inject a few mocks during test, to verify or at least peek on the current exchange contents.
Based on the docs and from the Apache Camel Cookbook. I've tried to use #MockEndpoints
Here's the route builder
#Component
public class MockedRouteStub extends RouteBuilder {
private static final Logger LOGGER = LoggerFactory.getLogger(MockedRouteStub.class);
#Override
public void configure() throws Exception {
from("direct:stub")
.choice()
.when().simple("${body} contains 'Camel'")
.setHeader("verified").constant(true)
.to("direct:foo")
.otherwise()
.to("direct:bar")
.end();
from("direct:foo")
.process(e -> LOGGER.info("foo {}", e.getIn().getBody()));
from("direct:bar")
.process(e -> LOGGER.info("bar {}", e.getIn().getBody()));
}
}
Here's my test (currently its a springboot project):
#RunWith(SpringRunner.class)
#SpringBootTest
#MockEndpoints
public class MockedRouteStubTest {
#Autowired
private ProducerTemplate producerTemplate;
#EndpointInject(uri = "mock:direct:foo")
private MockEndpoint mockCamel;
#Test
public void test() throws InterruptedException {
String body = "Camel";
mockCamel.expectedMessageCount(1);
producerTemplate.sendBody("direct:stub", body);
mockCamel.assertIsSatisfied();
}
}
message count is 0 and it looks more like #MockEndpoints is not triggered.
Also, logs indicate that the log is triggered
route.MockedRouteStub : foo Camel
An alternative i've tried is to use an advice:
...
#Autowired
private CamelContext context;
#Before
public void setup() throws Exception {
context.getRouteDefinitions().get(0).adviceWith(context, new AdviceWithRouteBuilder() {
#Override
public void configure() throws Exception {
mockEndpoints();
}
});
}
The startup logs indicate that advice is in place:
c.i.InterceptSendToMockEndpointStrategy : Adviced endpoint [direct://stub] with mock endpoint [mock:direct:stub]
But still my test fails with the message count = 0.

Posting the answer which worked for the setup that i have.
Without any changes to the RouteBuilder, the Test would look something like this:
#RunWith(CamelSpringBootRunner.class)
#SpringBootTest
#MockEndpoints
public class MockedRouteStubTest {
#Autowired
private ProducerTemplate producerTemplate;
#EndpointInject(uri = "mock:direct:foo")
private MockEndpoint mockCamel;
#Test
public void test() throws InterruptedException {
String body = "Camel";
mockCamel.expectedMessageCount(1);
producerTemplate.sendBody("direct:stub", body);
mockCamel.assertIsSatisfied();
}
}

Related

SpringBoot Junit testing for filters in Zuul

I'm new to Zuul J-unit testing. I have a couple of filters which is ChangeRequestEntityFilter and SessionFilter, Where I pasted my filtercode below. Can someone tell me how to write a Junit for the filter. I've searched and trying to use MockWire for the unit testing(Also I pasted my empty methods with basic annotations and WireMock port). I need at-least one proper example how this J-unit for Zuul works. I've referred the http://wiremock.org/docs/getting-started/ doc. Where I got what to do, but not how to do.
public class ChangeRequestEntityFilter extends ZuulFilter {
#Autowired
private UtilityHelperBean utilityHelperBean;
#Override
public boolean shouldFilter() {
// //avoid http GET request since it does'nt have any request body
return utilityHelperBean.isValidContentBody();
}
#Override
public int filterOrder() {
//given priority
}
#Override
public String filterType() {
// Pre
}
#Override
public Object run() {
RequestContext context = getCurrentContext();
try {
/** get values profile details from session */
Map<String, Object> profileMap = utilityHelperBean.getValuesFromSession(context,
CommonConstant.PROFILE.value());
if (profileMap != null) {
/** get new attributes need to add to the actual origin microservice request payload */
Map<String, Object> profileAttributeMap = utilityHelperBean.getProfileForRequest(context, profileMap);
/** add the new attributes in to the current request payload */
context.setRequest(new CustomHttpServletRequestWrapper(context.getRequest(), profileAttributeMap));
}
} catch (Exception ex) {
ReflectionUtils.rethrowRuntimeException(new IllegalStateException("ChangeRequestEntityFilter : ", ex));
}
return null;
}
}
I know ,I'm asking more. But give me any simple working complete example, I'm fine with it.
My current code with basic annotations and WireMock port.
#RunWith(SpringRunner.class)
#SpringBootTest
#DirtiesContext
#EnableZuulProxy
public class ChangeRequestEntityFilterTest {
#Rule
public WireMockRule wireMockRule = new WireMockRule(8080);
#Mock
ChangeRequestEntityFilter requestEntityFilter;
int port = wireMockRule.port();
#Test
public void changeRequestTest() {
}
}
Have you tried #MockBean?
https://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/test/mock/mockito/MockBean.html
"When #MockBean is used on a field, as well as being registered in the application context, the mock will also be injected into the field. Typical usage might be:"
#RunWith(SpringRunner.class)
public class ExampleTests {
#MockBean
private ExampleService service;
#Autowired
private UserOfService userOfService;
#Test
public void testUserOfService() {
given(this.service.greet()).willReturn("Hello");
String actual = this.userOfService.makeUse();
assertEquals("Was: Hello", actual);
}
#Configuration
#Import(UserOfService.class) // A #Component injected with ExampleService
static class Config {
}
}
Here there is another approach:
private ZuulPostFilter zuulPostFilter;
#Mock
private anotherService anotherService;
#Mock
private HttpServletRequest request;
#Before
public void before() {
MockitoAnnotations.initMocks(this);
MonitoringHelper.initMocks();
zuulPostFilter = new ZuulPostFilter(anotherService);
doNothing().when(anotherService).saveInformation(null, false);
}
#Test
public void postFilterTest() {
log.info("postFilterTest");
RequestContext context = new RequestContext();
context.setResponseDataStream(new ByteArrayInputStream("Test Stream".getBytes()));
context.setResponseGZipped(false);
RequestContext.testSetCurrentContext(context);
when(request.getScheme()).thenReturn("HTTP");
RequestContext.getCurrentContext().setRequest(request);
ZuulFilterResult result = zuulPostFilter.runFilter();
assertEquals(ExecutionStatus.SUCCESS, result.getStatus());
assertEquals("post", zuulPostFilter.filterType());
assertEquals(10, zuulPostFilter.filterOrder());
}
In this case you can test the filter and mock the services inside it without having to autowire it, the problem with the #autowired is that if you have services inside the filter, then it is going to be an integration test that is going to be more difficult to implement.

Unit testing Camel/RabbitMQ routes issue

I'm having issue unit testing a camel route which uses rabbitmq for the broker.
I've been researching for weeks but haven't found an effective way to do this.
Firstly, I was having an issue with NOT calling rabbitmq in my test, and to keep this a unit test and not an integration test. This was achieved by using advicewith and switch out the queue for mock queues.
However, with the following code the messages are not reaching the result or end queue (MOBILE_QUEUE).
java.lang.AssertionError: mock://result Received message count. Expected: <1> but was: <0>
Expected :<1>
Actual :<0>
Here is my route, which imports rabbitmq.class
from(TEST_QUEUE).to(MOBILE_QUEUE).routeId("test2phone");
My config rabbitmq.class
#Component
public class RabbitMQ extends Properties {
public final String TEST_QUEUE = CreateRabbitMQQueue("TestQueue", "camel");
public final String MOBILE_QUEUE = CreateRabbitMQQueue("MobileQueue", "camel");
public static String CreateRabbitMQQueue(String QueueName, String RoutingKey)
{
String hostv;
String portv;
String username;
String password;
hostv = "mq-staging";
portv = System.getenv("SERVICE_PORT_AMQP");
username = System.getenv("V_RABBIT_USERNAME");
password = System.getenv("V_RABBIT_PASSWORD");
UriComponentsBuilder uriBuilder = UriComponentsBuilder
.fromPath("/" )
.scheme("rabbitmq")
.host(hostv)
.port(portv)
.path("/" + QueueName)
.queryParam("username",username)
.queryParam("password", password)
.queryParam("routingKey",RoutingKey)
.queryParam("queue","Q" + QueueName);
return uriBuilder.toUriString();
}
}
And my unit test
#RunWith(CamelSpringRunner.class)
#MockEndpoints
#UseAdviceWith
#SpringBootTest
public class RouteTester extends CamelTestSupport {
String TEST_QUEUE;
String MOBILE_QUEUE;
#Autowired
Routes routes;
#Autowired
CamelContext context;
#Autowired
ProducerTemplate template;
#Before
public void setUp() throws Exception {
TEST_QUEUE = routes.getTEST_QUEUE();
MOBILE_QUEUE = routes.getMOBILE_QUEUE();
context.getRouteDefinition("test2phone").adviceWith(context, new Routes() {
#Override
public void configure() throws Exception {
interceptSendToEndpoint(TEST_QUEUE)
.skipSendToOriginalEndpoint()
.to("mock:testQ");
interceptSendToEndpoint(MOBILE_QUEUE)
.skipSendToOriginalEndpoint()
.to("mock:result");
}
});
context.start();
}
#Test
public void testTest() throws Exception {
String body = "hello123";
MockEndpoint resultEndpoint = context.getEndpoint("mock:result", MockEndpoint.class);
resultEndpoint.expectedMessageCount(1);
resultEndpoint.expectedBodiesReceived(body);
template.sendBody(TEST_QUEUE, body);
resultEndpoint.assertIsSatisfied();
}
#After
public void TearDown() throws Exception {
context.stop();
}
}
interceptSendToEndpoint is useful to intercepting output endpoint. You probably want replace input endpoint and intercept output endpoint. See AdviceWith.
This should work:
context.getRouteDefinition("test2phone").adviceWith(context, new AdviceWithRouteBuilder() {
#Override
public void configure() throws Exception {
replaceFromWith("direct:test");
interceptSendToEndpoint(MOBILE_QUEUE)
.skipSendToOriginalEndpoint()
.to("mock:result");
}
});
And test your route with:
template.sendBody("direct:test", body);

Camel Spring Boot MockEndpoint assertion not working as expected

My test application can start up normally with CamelSpringBootApplicationController. However, when I am working on the integration test, the assertion of MockEndpoint is not working as expected The snapshot of my test code is listed below. Am I doing anything wrong?
Application.java
#SpringBootApplication
public class Application {
....
public static final String DIRECT_BT_INPUT = "direct:btInput";
public static final String DIRECT_BT_OUTPUT = "direct:btOutput";
#Bean
public RouteBuilder RouteBuilder() {
return new RouteBuilder() {
#Override
public void configure() throws Exception {
from(DIRECT_BT_INPUT).log("${body}").to(DIRECT_BT_OUTPUT);
from(DIRECT_BT_OUTPUT).log("done");
}
};
}
}
BTRouteUnitTest.java
#RunWith(CamelSpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = Application.class)
#DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD)
#MockEndpoints(Application.DIRECT_BT_OUTPUT)
public class BTRouteIT {
#Autowired
protected CamelContext camelContext;
#EndpointInject(uri = "mock:" + Application.DIRECT_BT_OUTPUT)
protected MockEndpoint mockBtOutput;
#Produce(uri = Application.DIRECT_BT_INPUT)
protected ProducerTemplate producerTemplate;
#Test
public void test() throws InterruptedException {
mockBtOutput.expectedBodiesReceived("Hello");
producerTemplate.sendBody("Hello");
MockEndpoint.assertIsSatisfied(camelContext);
}
}
#MockEndpoint is not supported yet in Camel Spring Boot.
Workaround: move endpoint uris to properties file (in route definition use {{}}) and use different property file where you substitute original endpoint uri with mock:orginalUri.
You are testing with CamelSpringJUnit4ClassRunner in camel-test-spring. Camel spring test is for regular spring, not spring-boot.
Use SpringJUnit4ClassRunner test runner instead.

Using test application.properties file with CamelSpringTestSupport in Spring Boot

Prerequisites
Apache Tomcat 7
Spring 4.1.5.RELEASE
Spring Boot 1.2.2.RELEASE
Apache Camel 2.15.1
Problem
I am Using Spring Boot with a configuration class which is also used by EndpointSetup.
#SpringBootApplication
#Import({MyConfiguration.class, EndpointSetup.class})
public class MyFatJarRouter extends FatJarRouter { ... }
#Configuration
#ConfigurationProperties(prefix = "camel.route", ignoreUnknownFields = false)
public class MyConfiguration {
private List<String> brokerUrl = new ArrayList<>();
public List<String> getBrokerUrl() {return brokerUrl;}
public void setBrokerUrl(List<String> brokerUrl) {this.brokerUrl = brokerUrl;}
}
In production properties will be read from conf/application.properties by default.
I want to test my routes via CamelSpringTestSupport
So I have tried following:
I have placed a application.properties under test/resources/config/application.properties (--> in classpath of test)
then wrote following:
public class MyJmsTest extends CamelSpringTestSupport {
#Override
protected AbstractApplicationContext createApplicationContext() {
return new AnnotationConfigApplicationContext(MyFatJarRouter.class);
}
#Test
public void myTest() throws Exception {
...
}
}
In the example above the configuration is not read from the application.properties placed in test folder.
How can I read a test specific config file in my CamelSpringTestSupport Unit-Test?
I may be little late in answering, but there is a better way than hacking endpoints. The following solution uses toD introduced in Camel 2.16. I wrote a custom component "github" (there's an official one as well), and the following is how I test it. Note that I'm not using a single Camel proprietary annotation. To inject properties, I can either use the properties attribute in #SpringBootTest, or any of the other standard techniques available in Spring Boot.
Note that I'm using $simple{...} to avoid clash with Spring property resolution.
<rant>
And yes, Camel documentation sucks! They write it like release notes, with a section dedicated to each release, and don't seem to update the doc to keep up with the latest versions (the following technique is not documented). Imagine going to a restaurant and asking for the special, only to be told by the server about the special for the day before, and the week before, and so on. How about versioning the doc instead?
</rant>
#RunWith(CamelSpringBootRunner.class)
#SpringBootTest
#DirtiesContext(classMode = AFTER_EACH_TEST_METHOD)
public class GitHubRouteTest {
#Autowired
private CamelContext camelContext;
#Autowired
private ProducerTemplate template;
#Autowired
private GitHubClient gitHubClient;
#Test
public void testGitHubClientInvoked() throws InterruptedException {
template.sendBodyAndHeader("direct:start", "whatever",
"endpoint", "commits/test/test?username=test&password=test");
verify(gitHubClient).getCommitsForARepo(eq("test"), eq("master"), eq("test"), eq(20));
}
#SpringBootApplication
public static class TestApplication {
public static void main(String[] args) {
new SpringApplicationBuilder()
.sources(TestApplication.class)
.web(false)
.run(args);
}
#Bean
public RouteBuilder testRoute() {
return new RouteBuilder() {
#Override
public void configure() throws Exception {
from("direct:start")
.toD("github:$simple{in.header.endpoint}");
}
};
}
#Bean
public GitHubClient mockGitHubClient() {
GitHubClient mock = Mockito.mock(GitHubClient.class);
return mock;
}
}
}
I solved it by using standard spring unit-tests like this:
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = Application.class)
#ActiveProfiles("test") // Load applicaton-test.properties in test/resources/config/application-test.properties
#DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD) // cleanup spring context because jms broker does not exit properly
public class MyJmsTest {
private static final String MOCK_MY_ENDPOINT = "mock:myEndpoint";
#Autowired
CamelContext context;
#Autowired
ApplicationContext applicationContext;
#Autowired
ProducerTemplate producerTemplate;
#Before
public void configureMocks() throws Exception {
context.getRouteDefinition("MyRoute")
.adviceWith(context, new AdviceWithRouteBuilder() {
#Override
public void configure() throws Exception {
weaveByToString(".*myEndPointId.*")
.replace()
.to(MOCK_MY_ENDPOINT);
}
});
final MockEndpoint endpoint = context.getEndpoint(MOCK_MY_ENDPOINT, MockEndpoint.class);
endpoint.whenAnyExchangeReceived(new Processor() {
#Override
public void process(Exchange exchange) throws Exception {
InputStream inStream = getClass().getClassLoader().getResourceAsStream("xml/my.xml");
String in = context.getTypeConverter().convertTo(String.class, inStream);
exchange.getIn().setBody(in);
}
});
}
#Test
public void synchronousCallBasic_1() throws Exception {
final MyConfiguration MyConfiguration = applicationContext.getBean(MyConfiguration.class);
final String myMessageBody =
context.getTypeConverter().convertTo(String.class, getClass().getClassLoader()
.getResourceAsStream("xml/0010_example.xml"));
final Object myResult = producerTemplate.requestBody(MyConfiguration.getActiveMqSynchronousEndpointUri(), myMessageBody);
assertThat(myResult, notNullValue());
assertThat((String)myResult, is("<example>1</example>"));
}
}
I solved this issue, with a lot of annotation which I found here, and now the test properties are correctly injected:
#RunWith(CamelSpringBootRunner.class)
#SpringBootTest
#ActiveProfiles("test")
#EnableAutoConfiguration
#ComponentScan
#ContextConfiguration()
public class MessageDeliveryTest{
}
Also, the test properties file needs to be named application-{env}.properties, where "env" is the profile used here. For eg. for test the properties file should be application-test.properties

Testing Spring MVC #ExceptionHandler method with Spring MVC Test

I have the following simple controller to catch any unexpected exceptions:
#ControllerAdvice
public class ExceptionController {
#ExceptionHandler(Throwable.class)
#ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
#ResponseBody
public ResponseEntity handleException(Throwable ex) {
return ResponseEntityFactory.internalServerErrorResponse("Unexpected error has occurred.", ex);
}
}
I'm trying to write an integration test using Spring MVC Test framework. This is what I have so far:
#RunWith(MockitoJUnitRunner.class)
public class ExceptionControllerTest {
private MockMvc mockMvc;
#Mock
private StatusController statusController;
#Before
public void setup() {
this.mockMvc = MockMvcBuilders.standaloneSetup(new ExceptionController(), statusController).build();
}
#Test
public void checkUnexpectedExceptionsAreCaughtAndStatusCode500IsReturnedInResponse() throws Exception {
when(statusController.checkHealth()).thenThrow(new RuntimeException("Unexpected Exception"));
mockMvc.perform(get("/api/status"))
.andDo(print())
.andExpect(status().isInternalServerError())
.andExpect(jsonPath("$.error").value("Unexpected Exception"));
}
}
I register the ExceptionController and a mock StatusController in the Spring MVC infrastructure.
In the test method I setup an expectation to throw an exception from the StatusController.
The exception is being thrown, but the ExceptionController isn't dealing with it.
I want to be able to test that the ExceptionController gets exceptions and returns an appropriate response.
Any thoughts on why this doesn't work and how I should do this kind of test?
Thanks.
I just had the same issue and the following works for me:
#Before
public void setup() {
this.mockMvc = MockMvcBuilders.standaloneSetup(statusController)
.setControllerAdvice(new ExceptionController())
.build();
}
This code will add ability to use your exceptions controlled advice.
#Before
public void setup() {
this.mockMvc = standaloneSetup(commandsController)
.setHandlerExceptionResolvers(withExceptionControllerAdvice())
.setMessageConverters(new MappingJackson2HttpMessageConverter()).build();
}
private ExceptionHandlerExceptionResolver withExceptionControllerAdvice() {
final ExceptionHandlerExceptionResolver exceptionResolver = new ExceptionHandlerExceptionResolver() {
#Override
protected ServletInvocableHandlerMethod getExceptionHandlerMethod(final HandlerMethod handlerMethod,
final Exception exception) {
Method method = new ExceptionHandlerMethodResolver(ExceptionController.class).resolveMethod(exception);
if (method != null) {
return new ServletInvocableHandlerMethod(new ExceptionController(), method);
}
return super.getExceptionHandlerMethod(handlerMethod, exception);
}
};
exceptionResolver.afterPropertiesSet();
return exceptionResolver;
}
Since you are using stand alone setup test you need to provide exception handler manually.
mockMvc= MockMvcBuilders.standaloneSetup(adminCategoryController).setSingleView(view)
.setHandlerExceptionResolvers(getSimpleMappingExceptionResolver()).build();
I had same problem a few days back, you can see my problem and solution answered by myself here Spring MVC Controller Exception Test
Hoping my answer help you out
Use Spring MockMVC to emulate a servletContainer to a point where you can incorporate any request filtering or exception handling tests in your unit tests suite.
You can configure this setup with the following approach:
Given a custom RecordNotFound exception...
#ResponseStatus(value=HttpStatus.NOT_FOUND, reason="Record not found") //
public class RecordNotFoundException extends RuntimeException {
private static final long serialVersionUID = 8857378116992711720L;
public RecordNotFoundException() {
super();
}
public RecordNotFoundException(String message) {
super(message);
}
}
... and a RecordNotFoundExceptionHandler
#Slf4j
#ControllerAdvice
public class BusinessExceptionHandler {
#ExceptionHandler(value = RecordNotFoundException.class)
public ResponseEntity<String> handleRecordNotFoundException(
RecordNotFoundException e,
WebRequest request) {
//Logs
LogError logging = new LogError("RecordNotFoundException",
HttpStatus.NOT_FOUND,
request.getDescription(true));
log.info(logging.toJson());
//Http error message
HttpErrorResponse response = new HttpErrorResponse(logging.getStatus(), e.getMessage());
return new ResponseEntity<>(response.toJson(),
HeaderFactory.getErrorHeaders(),
response.getStatus());
}
...
}
Configure a tailored test context: set a #ContextConfiguration to specify the classes you need for your test. Set Mockito MockMvc as a servlet container emulator and set your tests fixture and dependencies.
#RunWith(SpringRunner.class)
#ContextConfiguration(classes = {
WebConfig.class,
HeaderFactory.class,
})
#Slf4j
public class OrganisationCtrlTest {
private MockMvc mvc;
private Organisation coorg;
#MockBean
private OrganisationSvc service;
#InjectMocks
private OrganisationCtrl controller = new OrganisationCtrl();
//Constructor
public OrganisationCtrlTest() {
}
....
Configure a mock MVC "servlet emulator": register handler beans in the context and build the mockMvc emulator (Note: there are two possible configuration: standaloneSetup or webAppContextSetup; refer to the documentation). The builder rightfully implements the Builder pattern so you can chain configuration commands for exception resolvers and handlers before calling build().
#Before
public void setUp() {
final StaticApplicationContext appContext = new StaticApplicationContext();
appContext.registerBeanDefinition("BusinessExceptionHandler",
new RootBeanDefinition(BusinessExceptionHandler.class, null, null));
//InternalExceptionHandler extends ResponseEntityExceptionHandler to //handle Spring internally throwned exception
appContext.registerBeanDefinition("InternalExceptionHandler",
new RootBeanDefinition(InternalExceptionHandler.class, null,
null));
MockitoAnnotations.initMocks(this);
mvc = MockMvcBuilders.standaloneSetup(controller)
.setHandlerExceptionResolvers(getExceptionResolver(appContext))
.build();
coorg = OrganisationFixture.getFixture("orgID", "name", "webSiteUrl");
}
....
Get the exception resolver
private ExceptionHandlerExceptionResolver getExceptionResolver(
StaticApplicationContext context) {
ExceptionHandlerExceptionResolver resolver = new ExceptionHandlerExceptionResolver();
resolver.getMessageConverters().add(
new MappingJackson2HttpMessageConverter());
resolver.setApplicationContext(context);
resolver.afterPropertiesSet();
return resolver;
}
Run your tests
#Test
public void testGetSingleOrganisationRecordAnd404() throws Exception {
System.out.println("testGetSingleOrganisationRecordAndSuccess");
String request = "/orgs/{id}";
log.info("Request URL: " + request);
when(service.getOrganisation(anyString())).
thenReturn(coorg);
this.mvc.perform(get(request)
.accept("application/json")
.andExpect(content().contentType(
.APPLICATION_JSON))
.andExpect(status().notFound())
.andDo(print());
}
....
}
Hope this helps.
Jake.
Try it;
#RunWith(value = SpringJUnit4ClassRunner.class)
#WebAppConfiguration
#ContextConfiguration(classes = { MVCConfig.class, CoreConfig.class,
PopulaterConfiguration.class })
public class ExceptionControllerTest {
private MockMvc mockMvc;
#Mock
private StatusController statusController;
#Autowired
private WebApplicationContext wac;
#Before
public void setup() {
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
}
#Test
public void checkUnexpectedExceptionsAreCaughtAndStatusCode500IsReturnedInResponse() throws Exception {
when(statusController.checkHealth()).thenThrow(new RuntimeException("Unexpected Exception"));
mockMvc.perform(get("/api/status"))
.andDo(print())
.andExpect(status().isInternalServerError())
.andExpect(jsonPath("$.error").value("Unexpected Exception"));
}
}
This is better:
((HandlerExceptionResolverComposite) wac.getBean("handlerExceptionResolver")).getExceptionResolvers().get(0)
And do not forget to scan for #ControllerAdvice beans in your #Configuration class:
#ComponentScan(basePackages = {"com.company.exception"})
...tested on Spring 4.0.2.RELEASE

Resources