Как проверить аспект с помощью SpringBootTest? - PullRequest
2 голосов
/ 26 июня 2019

Я создал простой аспект в Spring, используя Spring Boot 2.1.6.RELEASE. Это в основном записывает общее время, потраченное на метод.

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

Демонстрационное приложение с весенней загрузкой вызовет 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 test и 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, так как кажется, что он не запускается.

Чего-то не хватает, чтобы вызвать аспект в тесте? Или есть другие способы тестирования аспекта в весенней загрузке?

Ответы [ 2 ]

2 голосов
/ 26 июня 2019

Вам нужно начать @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 {
0 голосов
/ 02 июля 2019

Другое решение, которое, кажется, работает, добавляет AnnotationAwareAspectJAutoProxyCreator в classes из @SpringBootTest, хотя я не совсем уверен, почему.

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator;
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,
                            AnnotationAwareAspectJAutoProxyCreator.class })
public class DemoComponentFailTest {

  @Autowired
  private DemoComponent demoComponent;

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