Fabrício Lima
Fabrício Lima

Reputation: 111

Spring AOP Aspect not working using Mockito

I have an @Aspect that weaves the execution of all my controller action methods. It works fine when I run the system, but not in unit testing. I'm using Mockito and junit in the following way:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("file:**/spring-context.xml")
@WebAppConfiguration
public class UserControllerTest {        
    private MockMvc mockMvc;

    @Mock
    private RoleService roleService;

    @InjectMocks
    private UserController userController;

    @Before
    public void setUp() {
       MockitoAnnotations.initMocks(this);                    
       ...    
       mockMvc = MockMvcBuilders.standaloneSetup(userController).build();
    }    
    ...
}

with some @Test using mockMvc.perform().

And my Aspect are:

@Pointcut("within(@org.springframework.stereotype.Controller *)")
public void controller() { }

@Pointcut("execution(* mypackage.controller.*Controller.*(..))")
public void methodPointcut() { }

@Around("controller() && methodPointcut()")
...

Upvotes: 11

Views: 13254

Answers (2)

user3527787
user3527787

Reputation: 131

First it is necessary to use webAppContextSetup as Jason suggested:

@Autowired
private WebApplicationContext webApplicationContext;

@Before
public void setUp() throws Exception {
   ...
   mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
}

At this point the aspect should be triggered but Mockito will not inject mocks. This is because Spring AOP uses a proxy object and the mocks are being injected to this proxy object instead of the proxied object. To fix this it is necessary to unwrap the object and use ReflectionUtils instead of @InjectMocks annotation:

private MockMvc mockMvc;

@Mock
private RoleService roleService;

private UserController userController;

@Autowired
private WebApplicationContext webApplicationContext;

@Before
public void setUp() {
   MockitoAnnotations.initMocks(this);                    
   UserController unwrappedController = (UserController) unwrapProxy(userController);
   ReflectionTestUtils.setField(unwrappedController, "roleService", roleService);   
   mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
}

...

public static final Object unwrapProxy(Object bean) throws Exception {
/*
 * If the given object is a proxy, set the return value as the object
 * being proxied, otherwise return the given object.
 */
    if (AopUtils.isAopProxy(bean) && bean instanceof Advised) {
        Advised advised = (Advised) bean;
        bean = advised.getTargetSource().getTarget();
    }
    return bean;
}

At this point any call to when(...).thenReturn(...) should work properly.

It is explained here: http://kim.saabye-pedersen.org/2012/12/mockito-and-spring-proxies.html

Upvotes: 13

Biju Kunjummen
Biju Kunjummen

Reputation: 49935

You are probably using Spring AOP, in which case the bean has to be a Spring bean for AOP to work, by not autowiring in the controller it is bypassing the Spring AOP mechanism totally.

I think the fix should be to simply inject in the controller

 @Autowired
 @InjectMocks
 private UserController userController;

Upvotes: 0

Related Questions