Pregunta

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?

¿Fue útil?

Solución 2

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.

Otros consejos

Is the aspect injected with the same mocked instance of AdvertisementService?

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top