如何用SpringBootTest测试一个方面?

时间:2019-06-25 23:02:33

标签: java spring-boot aop aspectj

我使用Spring Boot 2.1.6.RELEASE在Spring中创建了一个简单的方面。 它基本上记录了花费在方法上的总时间。

@Aspect
@Component
public class TimeLoggerAspect {

  private static final Logger log = LoggerFactory.getLogger(TimeLoggerAspect.class);

  @Around("@annotation(demo.TimeLogger)")
  public Object methodTimeLogger(ProceedingJoinPoint joinPoint) 
          throws Throwable {
    long startTime = System.currentTimeMillis();

    Object proceed = joinPoint.proceed();

    long totalTime = System.currentTimeMillis() - startTime;
    log.info("Method " + joinPoint.getSignature() + ": " + totalTime + "ms");

    return proceed;
  }
}

该方面由TimeLogger注释触发

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface TimeLogger {
}

并在这样的组件中使用

@Component
public class DemoComponent {
  @TimeLogger
  public void sayHello() {
    System.out.println("hello");
  }
}

Spring Boot演示应用程序将通过sayHello界面的run方法调用CommandLineRunner

@SpringBootApplication
public class DemoApplication implements CommandLineRunner {

  @Autowired
  private DemoComponent demoComponent;

  public static void main(String[] args) {
    SpringApplication.run(DemoApplication.class, args);
  }

  @Override
  public void run(String... args) throws Exception {
    demoComponent.sayHello();
  }
}

为完整起见,我在build.gradle中添加了修改内容:添加了用于aop,spring测试和jupiter(junit)的库。

    compile("org.springframework.boot:spring-boot-starter-aop")

    testCompile("org.springframework.boot:spring-boot-starter-test")
    testCompile("org.junit.jupiter:junit-jupiter-api")
    testRuntime("org.junit.jupiter:junit-jupiter-engine")

运行该应用程序将输出(为便于阅读而进行了修剪)

hello
... TimeLoggerAspect : Method void demo.DemoComponent.sayHello(): 4ms

到目前为止,太好了。现在,我基于@SpringBootTest批注和木星创建一个测试。

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit.jupiter.SpringExtension;

@ExtendWith(SpringExtension.class)
@SpringBootTest(classes = {DemoComponent.class, TimeLoggerAspect.class})
public class DemoComponentFailTest {

  @Autowired
  private DemoComponent demoComponent;

  @Test
  public void shouldLogMethodTiming() {
      demoComponent.sayHello();
  }
}

在这里我得到了输出

hello

TimeLoggerAspect没有输出,因为似乎没有被触发。

是否缺少某些东西可以触发测试中的方面?还是有其他方法可以在Spring Boot中测试方面?

4 个答案:

答案 0 :(得分:2)

您需要启动@SpringBootApplication。但是,它不一定是您用来在生产中启动应用程序的人。它只能是一种特殊的测试,可以在测试源而不是src中出现。

@SpringBootApplication
@ComponentScan(basePackageClasses = {DemoComponent.class, TimeLoggerAspect.class})
public class SpringBootTestMain {
    public static void main(String[] args) {
        SpringApplication.run(SpringBootTestMain.class, args);
    }

}

然后在您的测试中,这是您需要列出的唯一课程。

@ExtendWith(SpringExtension.class)
@SpringBootTest(classes = SpringBootTestMain.class)
public class DemoComponentFailTest {

答案 1 :(得分:2)

您必须将@EnableAspectJAutoProxy与文件@Configuration一起使用,该文件使用@Aspect声明Bean。

@Aspect
@Configuration
@EnableAspectJAutoProxy
public class TimeLoggerAspect {

  private static final Logger log = LoggerFactory.getLogger(TimeLoggerAspect.class);

  @Around("@annotation(demo.TimeLogger)")
  public Object methodTimeLogger(ProceedingJoinPoint joinPoint) 
          throws Throwable {
    long startTime = System.currentTimeMillis();

    Object proceed = joinPoint.proceed();

    long totalTime = System.currentTimeMillis() - startTime;
    log.info("Method " + joinPoint.getSignature() + ": " + totalTime + "ms");

    return proceed;
  }
}

我认为那样就可以了。

答案 2 :(得分:1)

我有类似的问题。我的方面是监听控制器方法。为了激活它,导入AnnotationAwareAspectJAutoProxyCreator可以达到目的:

@RunWith(SpringRunner.class)
@Import(AnnotationAwareAspectJAutoProxyCreator.class) // activate aspect
@WebMvcTest(MyController.class)
public class MyControllerTest {

    ...

}

答案 3 :(得分:0)

似乎可行的另一种解决方案是,在*的{​​{1}}中添加 AnnotationAwareAspectJAutoProxyCreator ,尽管我不确定为什么。

classes