【问题标题】:Spring AOP Aspect not working using MockitoSpring AOP 方面无法使用 Mockito
【发布时间】:2013-06-03 17:26:13
【问题描述】:

我有一个@Aspect,它编织了我所有控制器操作方法的执行。当我运行系统时它工作正常,但在单元测试中却不行。我通过以下方式使用 Mockito 和 junit:

@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();
    }    
    ...
}

一些@Test 使用mockMvc.perform()

我的观点是:

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

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

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

【问题讨论】:

  • 我也有同样的问题。我注意到如果您使用备用webAppContextSetup 而不是standaloneSetup,方面会触发,但在这种情况下,模拟不会注入控制器。我还没有弄清楚如何让两者都工作

标签: spring junit aop mockito


【解决方案1】:

首先需要按照 Jason 的建议使用 webAppContextSetup:

@Autowired
private WebApplicationContext webApplicationContext;

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

此时应该触发方面,但 Mockito 不会注入模拟。这是因为 Spring AOP 使用代理对象,并且模拟被注入到这个代理对象而不是代理对象。要解决这个问题,需要解开对象并使用 ReflectionUtils 而不是 @InjectMocks 注释:

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;
}

此时对 when(...).thenReturn(...) 的任何调用都应该正常工作。

这里解释一下:http://kim.saabye-pedersen.org/2012/12/mockito-and-spring-proxies.html

【讨论】:

  • 不错!我使用泛型返回一个类型化的对象......即<T> T unwrapProxy(T bean)
【解决方案2】:

您可能正在使用 Spring AOP,在这种情况下,bean 必须是 Spring bean 才能使 AOP 工作,通过不在控制器中自动装配,它完全绕过了 Spring AOP 机制。

我认为解决方法应该是简单地注入控制器

 @Autowired
 @InjectMocks
 private UserController userController;

【讨论】:

  • 查看代码示例。 OP 已经完全按照您的建议行事。
  • 是的,错过了示例中的@Autowire注解,我现在已经添加进去了
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-12-26
  • 1970-01-01
相关资源
最近更新 更多