I have a springboot project with controllers and servies. And a GlobalExceptionHandler like -
public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {
#ExceptionHandler(DataIntegrityViolationException.class)
public ResponseEntity<Object> handle(DataIntegrityViolationException e, WebRequest request) {
....
String requestPath = ((ServletWebRequest)request).getRequest().getRequestURI();
// I am using this requestPath in my output from springboot
...
}
}
Can someone please tell me how to write mock this in my unit test class
((ServletWebRequest)request).getRequest().getRequestURI()
Unfortunately there is no support for subbing final methods in Mockito. You can use a other mocking framework like PowerMock.
I prefer in this cases to eliminate the need of mocking with an protected method:
public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {
#ExceptionHandler(DataIntegrityViolationException.class)
public ResponseEntity<Object> handle(final DataIntegrityViolationException e, final WebRequest request) {
final String requestPath = getRequestUri(request);
return ResponseEntity.ok().body(requestPath);
}
protected String getRequestUri(final WebRequest request) {
return ((ServletWebRequest) request).getRequest().getRequestURI();
}
}
And anonymous class in test:
public class GlobalExceptionHandlerTests {
private final GlobalExceptionHandler handler = new GlobalExceptionHandler() {
#Override
protected String getRequestUri(final org.springframework.web.context.request.WebRequest request) {
return "http://localhost.me";
};
};
#Test
void test() throws Exception {
final ResponseEntity<Object> handled = handler.handle(new DataIntegrityViolationException(""),
null);
assertEquals("http://localhost.me", handled.getBody());
}
}
I have an issue related to HandlerInterceptorAdapter.
Interceptor:
#Component
public class RequestInterceptor extends HandlerInterceptorAdapter {
#Override
public boolean preHandle(final HttpServletRequest request, final HttpServletResponse response, final Object handler)
throws Exception {
//some logic
return true;
}
}
WebMvcConfigurer
#Configuration
public class FsWebMvcConfigurer implements WebMvcConfigurer {
private static final String API_PATTERN = "/**/api/**/";
private final RequestInterceptor requestInterceptor;
#Autowired
public FsWebMvcConfigurer(final RequestInterceptor requestInterceptor) {
this.requestInterceptor = requestInterceptor;
}
#Override
public void addInterceptors(final InterceptorRegistry registry) {
registry.addInterceptor(requestInterceptor).addPathPatterns(API_PATTERN);
}
}
And it works as expected - every request with pattern /**/api/**/ is getting intercepted.
Unfortunetly it also works for the endpoints that are not registered - I don't want that kind of behaviour. How can I specify that the registered interceptor should only work with registered mappings?
Note: I don't want to specify exactly every existing endpoint by myself (e.g adding all as pattern)
I've created following component to add X-Frame-Options into each response:
#Component
public class SecurityInterceptor extends HandlerInterceptorAdapter {
#PostConstruct
public void init(){
System.out.println("init");
}
#Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
response.addHeader("X-Frame-Options", "DENY");
}
}
method init executes on startup thus spring knows about this.
Also I have following rest service:
#PostMapping("/rest_upload")
public DeferredResult<ResponseEntity> upload(#RequestParam("file") MultipartFile multipartFile, HttpServletRequest request) throws IOException {
final DeferredResult<ResponseEntity> deferredResult = new DeferredResult<>();
...
return deferredResult;
}
Unfortunately postHandle method is not invoking.
How can I correct it?
Spring knows about your Interceptor as just a bean and nothing more. You need to register it with InterceptorRegistry so that it is called as part of interceptors.
#Configuration
public class WebMvcConfig extends WebMvcConfigurerAdapter {
#Autowired
SecurityInterceptor securityInterceptor;
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(securityInterceptor);
}
}
You need a configuration class that extends WebMvcConfigurerAdapter and overrides the addInterceptor method:
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new SecurityInterceptor());
}
You also need to make sure you have enabled WebMvc in Spring.
I have a jersey web service. I want to write test cases for it.
My service is
#Path(value = "/mock")
#Component
public class MockService
{
private static Log log = LogFactory.getLog(MockService.class);
#POST
#Path(value = "/{mockrequest:ABCD}")
#Produces(MediaType.JSON)
public Response mockOKResponse(#Context ContainerRequestContext request, #PathParam("mockrequest") EnumMockService mockService)
{
return Response.ok().build();
}
#GET
#Path(value = "/{mockrequest}")
#Produces("application/pdf")
public Response mockProducesPDF(#Context ContainerRequestContext request, #PathParam("mockrequest") EnumMockService mockService)
{
MockAccountTable testccount = jdbcTestAcountDao.getTestAccountResponseBlob(mockService.toString());
byte[] responseBlob = testccount != null ? testccount.getResponseBlob() : null;
return Response.ok(responseBlob).build();
}
}
I am planing to write test case for this.Which calls specific method based on the specific reuest.
#RunWith(MockitoJUnitRunner.class)
public class TestMockService
extends TestCaseSrs
{
private MockService mockService = new MockService();
#Override
#Before
public void prepare()
throws Exception
{
MockitoAnnotations.initMocks(this);
}
#Test
public void testGetIncreasedHardwares()
{
//dynamically call method based on request
}
}
I am not sure how to set request type here to call method accordingly rather than calling method directly.
It would be great if some one can help me with the approach.
I ran into a problem the other day where a #Valid annotation was accidentally removed from a controller class. Unfortunately, it didn't break any of our tests. None of our unit tests actually exercise the Spring AnnotationMethodHandlerAdapter pathway. We just test our controller classes directly.
How can I write a unit or integration test that will correctly fail if my #MVC annotations are wrong? Is there a way I can ask Spring to find and exercise the relevant controller with a MockHttpServlet or something?
I write integration tests for this kind of thing. Say you have a bean with validation annotations:
public class MyForm {
#NotNull
private Long myNumber;
...
}
and a controller that handles the submission
#Controller
#RequestMapping("/simple-form")
public class MyController {
private final static String FORM_VIEW = null;
#RequestMapping(method = RequestMethod.POST)
public String processFormSubmission(#Valid MyForm myForm,
BindingResult result) {
if (result.hasErrors()) {
return FORM_VIEW;
}
// process the form
return "success-view";
}
}
and you want to test that the #Valid and #NotNull annotations are wired correctly:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration({"file:web/WEB-INF/application-context.xml",
"file:web/WEB-INF/dispatcher-servlet.xml"})
public class MyControllerIntegrationTest {
#Inject
private ApplicationContext applicationContext;
private MockHttpServletRequest request;
private MockHttpServletResponse response;
private HandlerAdapter handlerAdapter;
#Before
public void setUp() throws Exception {
this.request = new MockHttpServletRequest();
this.response = new MockHttpServletResponse();
this.handlerAdapter = applicationContext.getBean(HandlerAdapter.class);
}
ModelAndView handle(HttpServletRequest request, HttpServletResponse response)
throws Exception {
final HandlerMapping handlerMapping = applicationContext.getBean(HandlerMapping.class);
final HandlerExecutionChain handler = handlerMapping.getHandler(request);
assertNotNull("No handler found for request, check you request mapping", handler);
final Object controller = handler.getHandler();
// if you want to override any injected attributes do it here
final HandlerInterceptor[] interceptors =
handlerMapping.getHandler(request).getInterceptors();
for (HandlerInterceptor interceptor : interceptors) {
final boolean carryOn = interceptor.preHandle(request, response, controller);
if (!carryOn) {
return null;
}
}
final ModelAndView mav = handlerAdapter.handle(request, response, controller);
return mav;
}
#Test
public void testProcessFormSubmission() throws Exception {
request.setMethod("POST");
request.setRequestURI("/simple-form");
request.setParameter("myNumber", "");
final ModelAndView mav = handle(request, response);
// test we're returned back to the form
assertViewName(mav, "simple-form");
// make assertions on the errors
final BindingResult errors = assertAndReturnModelAttributeOfType(mav,
"org.springframework.validation.BindingResult.myForm",
BindingResult.class);
assertEquals(1, errors.getErrorCount());
assertEquals("", errors.getFieldValue("myNumber"));
}
See my blog post on integration testing Spring's MVC annotations
Sure. There's no reason why your test can't instantiate its own DispatcherServlet, inject it with the various items which it would have in a container (e.g. ServletContext), including the location of the context definition file.
Spring comes with a variety of servlet-related MockXYZ classes for this purpose, including MockServletContext, MockHttpServletRequest and MockHttpServletResponse. They're not really "mock" objects in the usual sense, they're more like dumb stubs, but they do the job.
The servlet's test context would have the usual MVC-related beans, plus your beans to test. Once the servlet is initialized, create the mock requests and responses, and feed them into the servet's service() method. If request gets routed correctly, you can check the results as written to the mock response.
In upcoming spring 3.2 (SNAPSHOT available) or with spring-test-mvc (https://github.com/SpringSource/spring-test-mvc) you can do it like this:
first we emulate Validation as we do not want to test the validator, just want to know if validation is called.
public class LocalValidatorFactoryBeanMock extends LocalValidatorFactoryBean
{
private boolean fakeErrors;
public void fakeErrors ( )
{
this.fakeErrors = true;
}
#Override
public boolean supports ( Class<?> clazz )
{
return true;
}
#Override
public void validate ( Object target, Errors errors, Object... validationHints )
{
if (fakeErrors)
{
errors.reject("error");
}
}
}
this is our test class:
#RunWith(SpringJUnit4ClassRunner.class)
#WebAppConfiguration
#ContextConfiguration
public class RegisterControllerTest
{
#Autowired
private WebApplicationContext wac;
private MockMvc mockMvc;
#Autowired
#InjectMocks
private RegisterController registerController;
#Autowired
private LocalValidatorFactoryBeanMock validator;
#Before
public void setup ( )
{
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
// if you want to inject mocks into your controller
MockitoAnnotations.initMocks(this);
}
#Test
public void testPostValidationError ( ) throws Exception
{
validator.fakeErrors();
MockHttpServletRequestBuilder post = post("/info/register");
post.param("name", "Bob");
ResultActions result = getMockMvc().perform(post);
// no redirect as we have errors
result.andExpect(view().name("info/register"));
}
#Configuration
#Import(DispatcherServletConfig.class)
static class Config extends WebMvcConfigurerAdapter
{
#Override
public Validator getValidator ( )
{
return new LocalValidatorFactoryBeanMock();
}
#Bean
RegisterController registerController ( )
{
return new RegisterController();
}
}
}