Github地址html
Spring提供了一套AOP工具,可是当你把各类Aspect写完以后,如何肯定这些Aspect都正确的应用到目标Bean上了呢?本章将举例说明如何对Spring AOP作测试。java
首先先来看咱们事先定义的Bean以及Aspect。git
FooServiceImpl:github
@Component public class FooServiceImpl implements FooService { private int count; @Override public int incrementAndGet() { count++; return count; } }
FooAspect:spring
@Component @Aspect public class FooAspect { @Pointcut("execution(* me.chanjar.aop.service.FooServiceImpl.incrementAndGet())") public void pointcut() { } @Around("pointcut()") public int changeIncrementAndGet(ProceedingJoinPoint pjp) { return 0; } }
能够看到FooAspect
会修改FooServiceImpl.incrementAndGet
方法的返回值,使其返回0。segmentfault
最简单的测试方法就是直接调用FooServiceImpl.incrementAndGet
,看看它是否使用返回0。api
SpringAop_1_Test:ide
@ContextConfiguration(classes = { SpringAopTest.class, AopConfig.class }) public class SpringAop_1_Test extends AbstractTestNGSpringContextTests { @Autowired private FooService fooService; @Test public void testFooService() { assertNotEquals(fooService.getClass(), FooServiceImpl.class); assertTrue(AopUtils.isAopProxy(fooService)); assertTrue(AopUtils.isCglibProxy(fooService)); assertEquals(AopProxyUtils.ultimateTargetClass(fooService), FooServiceImpl.class); assertEquals(AopTestUtils.getTargetObject(fooService).getClass(), FooServiceImpl.class); assertEquals(AopTestUtils.getUltimateTargetObject(fooService).getClass(), FooServiceImpl.class); assertEquals(fooService.incrementAndGet(), 0); assertEquals(fooService.incrementAndGet(), 0); } }
先看这段代码:工具
assertNotEquals(fooService.getClass(), FooServiceImpl.class); assertTrue(AopUtils.isAopProxy(fooService)); assertTrue(AopUtils.isCglibProxy(fooService)); assertEquals(AopProxyUtils.ultimateTargetClass(fooService), FooServiceImpl.class); assertEquals(AopTestUtils.getTargetObject(fooService).getClass(), FooServiceImpl.class); assertEquals(AopTestUtils.getUltimateTargetObject(fooService).getClass(), FooServiceImpl.class);
这些是利用Spring提供的AopUtils、AopTestUtils和AopProxyUtils来判断FooServiceImpl
Bean是否被代理了(Spring AOP的实现是经过动态代理来作的)。测试
可是证实FooServiceImpl
Bean被代理并不意味着FooAspect
生效了(假设此时有多个@Aspect
),那么咱们还须要验证FooServiceImpl.incrementAndGet
的行为:
assertEquals(fooService.incrementAndGet(), 0); assertEquals(fooService.incrementAndGet(), 0);
可是总有一些时候咱们是没法经过例子1的方法来测试Bean是否被正确的advised的:
advised方法没有返回值
Aspect不会修改advised方法的返回值(好比:作日志)
那么这个时候怎么测试呢?此时咱们就须要用到Mockito的Spy方法结合Spring Testing工具来测试。
@ContextConfiguration(classes = { SpringAop_2_Test.class, AopConfig.class }) @TestExecutionListeners(listeners = MockitoTestExecutionListener.class) public class SpringAop_2_Test extends AbstractTestNGSpringContextTests { @SpyBean private FooAspect fooAspect; @Autowired private FooService fooService; @Test public void testFooService() { // ... verify(fooAspect, times(2)).changeIncrementAndGet(any()); } }
这段代码和例子1有三点区别:
启用了MockitoTestExecutionListener
,这样可以开启Mockito的支持(回顾一下Chapter 3: 使用Mockito)
@SpyBean private FooAspect fooAspect
,这样可以声明一个被Mockito.spy过的Bean
verify(fooAspect, times(2)).changeIncrementAndGet(any())
,使用Mockito测试FooAspect.changeIncrementAndGet
是否被调用了两次
上面的测试代码测试的是FooAspect
的行为,而不是FooServiceImpl
的行为,这种测试方法更为通用。
上面两个例子使用的是Spring Testing工具,下面举例Spring Boot Testing工具如何测AOP(其实大同小异):
@SpringBootTest(classes = { SpringBootAopTest.class, AopConfig.class }) @TestExecutionListeners(listeners = MockitoTestExecutionListener.class) public class SpringBootAopTest extends AbstractTestNGSpringContextTests { @SpyBean private FooAspect fooAspect; @Autowired private FooService fooService; @Test public void testFooService() { // ... verify(fooAspect, times(2)).changeIncrementAndGet(any()); } }