Reputation: 24689
I am unit testing the following Spring MVC controller method:
@RequestMapping(value = "/advertisement/family/edit/{advertisementId}", method = RequestMethod.GET, produces = "text/html")
@AdvertisementExistsAndBelongsToMemberCheck
public String editFamilyAdvertisementForm(@ModelAttribute FamilyAdvertisementInfo familyAdvertisementInfo, @PathVariable long advertisementId, Model model, @CurrentMember Member member) {
FamilyAdvertisement advertisement = advertisementService.findFamilyAdvertisement(advertisementId);
familyAdvertisementInfo.setFamilyAdvertisement(advertisement);
populateFamilyAdvertisementModel(model, familyAdvertisementInfo, member);
return "advertisement/family/edit";
}
The custom annotation (@AdvertisementExistsAndBelongsToMemberCheck
) above basically is advised by an aspect as follows:
before(long advertisementId, Member member) : advertisementBelongsToMemberControllerCheck(advertisementId, member) {
if (!advertisementService.advertisementExistsAndBelongsToMember(advertisementId, member)) {
throw new AccessDeniedException("Advertisement does not belong to member!");
}
}
If an AccessDeniedException
is thrown, then the following controller advice exception handler kicks in:
@ExceptionHandler(AccessDeniedException.class)
@ResponseStatus(value = HttpStatus.FORBIDDEN)
public String accessDeniedException(AccessDeniedException e) {
return "error/403";
}
Now, here is how I am trying to test the above controller method:
@ContextConfiguration
@WebAppConfiguration
@RunWith(SpringJUnit4ClassRunner.class)
public class AdvertisementControllerTest {
@Autowired
private WebApplicationContext ctx;
private MockMvc mockMvc;
@Autowired
private AdvertisementService advertisementService;
@Before
public void setup() {
mockMvc = webAppContextSetup(ctx).build();
when(advertisementService.advertisementExistsAndBelongsToMember(eq(111), any(Member.class))).thenReturn(Boolean.FALSE);
when(advertisementService.advertisementExistsAndBelongsToMember(eq(222), any(Member.class))).thenReturn(Boolean.TRUE);
}
@Test
public void shouldAllow() throws Exception {
mockMvc.perform(get("/advertisement/family/edit/222"))//
.andDo(print())//
.andExpect(status().isOk());
}
@Configuration
@EnableSpringConfigured
static class testConfiguration {
@Bean
public AdvertisementController advertisementController() {
return new AdvertisementController();
}
@Bean
public InternalResourceViewResolver getInternalResourceViewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/pages/");
resolver.setSuffix(".jsp");
return resolver;
}
@Bean
public AdvertisementService advertisementService() {
return mock(AdvertisementService.class);
}
}
}
The test systematically fails with the following stacktrace:
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.springframework.security.access.AccessDeniedException: Advertisement does not belong to member!
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:948)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:827)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:621)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:812)
at org.springframework.test.web.servlet.TestDispatcherServlet.service(TestDispatcherServlet.java:66)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
at org.springframework.mock.web.MockFilterChain$ServletFilterProxy.doFilter(MockFilterChain.java:168)
at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:136)
at org.springframework.test.web.servlet.MockMvc.perform(MockMvc.java:134)
at com.bignibou.tests.controller.advertisement.AdvertisementControllerTest.shouldAllow(AdvertisementControllerTest.java:64)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:74)
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:83)
at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:231)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:88)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71)
at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:174)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
Caused by: org.springframework.security.access.AccessDeniedException: Advertisement does not belong to member!
at com.bignibou.aop.AdvertisementExistsAndBelongsToMemberCheckAspect.ajc$before$com_bignibou_aop_AdvertisementExistsAndBelongsToMemberCheckAspect$2$3edd453b(AdvertisementExistsAndBelongsToMemberCheckAspect.aj:34)
at com.bignibou.controller.advertisement.AdvertisementController.editFamilyAdvertisementForm(AdvertisementController.java:56)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.invokeHandlerMethod(HandlerMethodInvoker.java:176)
at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.invokeHandlerMethod(AnnotationMethodHandlerAdapter.java:440)
at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.handle(AnnotationMethodHandlerAdapter.java:428)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:925)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:856)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:936)
... 38 more
I am not sure what I am getting wrong with Mockito...
Note that I did specify /222
in the path, indicating that my mock should return true in the aspect and allow the controller method to proceed. However, this is not the case.
Can anyone please help?
Upvotes: 0
Views: 3031
Reputation: 24689
The issue is that the type of the argument was a long
and I passed an int
.
Changing to:
when(advertisementService.advertisementExistsAndBelongsToMember(eq(222L), any(Member.class))).thenReturn(Boolean.TRUE);
and:
@Test
public void shouldAllow() throws Exception {
mockMvc.perform(get("/advertisement/family/edit/{advertisementId}", 222L))//
.andDo(print())//
.andExpect(status().isOk());
}
sorted the issue.
Upvotes: 1
Reputation: 4663
Is the aspect injected with the same mocked instance of AdvertisementService?
Upvotes: 1