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