资讯专栏INFORMATION COLUMN

Spring、Spring Boot和TestNG测试指南 - 测试AOP

changfeng1050 / 2918人阅读

摘要:首先先来看我们事先定义的以及。可以看到会修改方法的返回值,使其返回。例子测试的行为最简单的测试方法就是直接调用,看看它是否使用返回。先看这段代码这些是利用提供的和来判断是否被代理了的实现是通过动态代理来做的。

Github地址

Spring提供了一套AOP工具,但是当你把各种Aspect写完之后,如何确定这些Aspect都正确的应用到目标Bean上了呢?本章将举例说明如何对Spring AOP做测试。

首先先来看我们事先定义的Bean以及Aspect。

FooServiceImpl:

@Component
public class FooServiceImpl implements FooService {

  private int count;

  @Override
  public int incrementAndGet() {
    count++;
    return count;
  }

}

FooAspect:

@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。

例子1:测试FooService的行为

最简单的测试方法就是直接调用FooServiceImpl.incrementAndGet,看看它是否使用返回0。

SpringAop_1_Test:

@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);
例子2:测试FooAspect的行为

但是总有一些时候我们是无法通过例子1的方法来测试Bean是否被正确的advised的:

advised方法没有返回值

Aspect不会修改advised方法的返回值(比如:做日志)

那么这个时候怎么测试呢?此时我们就需要用到Mockito的Spy方法结合Spring Testing工具来测试。

SpringAop_2_Test:

@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的行为,这种测试方法更为通用。

例子3:Spring Boot的例子

上面两个例子使用的是Spring Testing工具,下面举例Spring Boot Testing工具如何测AOP(其实大同小异):

SpringBootAopTest:

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

  }

}
参考文档

Aspect Oriented Programming with Spring

AopUtils

AopTestUtils

AopProxyUtils

spring源码EnableAspectJAutoProxyTests

spring源码AbstractAspectJAdvisorFactoryTests

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/70359.html

相关文章

  • SpringSpring BootTestNG测试指南 - 测试Spring MVC

    摘要:地址提供了,能够很方便的来测试。同时也提供了更进一步简化了测试需要的配置工作。本章节将分别举例说明在不使用和使用下如何对进行测试。例子测试的关键是使用对象,利用它我们能够在不需启动容器的情况下测试的行为。 Github地址 Spring Testing Framework提供了Spring MVC Test Framework,能够很方便的来测试Controller。同时Spring...

    andong777 评论0 收藏0
  • SpringSpring BootTestNG测试指南 - @OverrideAutoConfi

    摘要:因为只有这样才能够在测试环境下发现生产环境的问题,也避免出现一些因为配置不同导致的奇怪问题。而方法则能够不改变原有配置不提供新的配置的情况下,就能够关闭。 Github地址 在Chapter 1: 基本用法 - 使用Spring Boot Testing工具里提到: 除了单元测试(不需要初始化ApplicationContext的测试)外,尽量将测试配置和生产配置保持一致。比如如果生产...

    elisa.yang 评论0 收藏0
  • SpringSpring BootTestNG测试指南 - @JsonTest

    摘要:地址是提供的方便测试序列化反序列化的测试工具,在的文档中有一些介绍。例子简单例子源代码见使用通包下的文件测试结果是否正确或者使用基于的校验例子测试可以用来测试。这个例子里使用了自定义的测试代码例子使用事实上也可以配合一起使用。 Github地址 @JsonTest是Spring Boot提供的方便测试JSON序列化反序列化的测试工具,在Spring Boot的文档中有一些介绍。 需要注...

    Hegel_Gu 评论0 收藏0
  • SpringSpring BootTestNG测试指南 - 使用Spring Testing工具

    摘要:源代码见需要注意的是,如果是专供某个测试类使用的话,把它放到外部并不是一个好主意,因为它有可能会被扫描到,从而产生一些奇怪的问题。 Github地址 既然我们现在开发的是一个Spring项目,那么肯定会用到Spring Framework的各种特性,这些特性实在是太好用了,它能够大大提高我们的开发效率。那么自然而然,你会想在测试代码里也能够利用Spring Framework提供的特...

    Maxiye 评论0 收藏0
  • SpringSpring BootTestNG测试指南 - 共享测试配置

    摘要:地址在使用工具中提到在测试代码之间尽量做到配置共用。本章将列举几种共享测试配置的方法我们可以将测试配置放在一个里,然后在测试或中引用它。也可以利用的及自定义机制,提供自己的用在测试配置上。 Github地址 在使用Spring Boot Testing工具中提到: 在测试代码之间尽量做到配置共用。...能够有效利用Spring TestContext Framework的缓存机制,Ap...

    CHENGKANG 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<