如何用SpringBootTest测试一个方面?
How to test an aspect with SpringBootTest?
我使用 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 引导演示应用程序将通过 CommandLineRunner
接口的 run
方法调用 sayHello
。
@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
注释和 jupiter 的测试。
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 引导中测试方面吗?
您需要开始 @SpringBootApplication
。但是,它不一定是您用来在生产环境中启动应用程序的那个。它可以是仅用于此测试的特殊版本,并且可以在您的测试源根目录中而不是您的 src 中。
@SpringBootApplication
@ComponentScan(basePackageClasses = {DemoComponent.class, TimeLoggerAspect.class})
public class SpringBootTestMain {
public static void main(String[] args) {
SpringApplication.run(SpringBootTestMain.class, args);
}
}
那么在您的测试中,这是您唯一需要列出的 class。
@ExtendWith(SpringExtension.class)
@SpringBootTest(classes = SpringBootTestMain.class)
public class DemoComponentFailTest {
另一个似乎有效的解决方案是在 @SpringBootTest
的 classes
中添加 AnnotationAwareAspectJAutoProxyCreator
,尽管我不太确定为什么。
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();
}
}
我有类似的问题。我的方面正在监听控制器方法。要激活它,导入 AnnotationAwareAspectJAutoProxyCreator
就可以了:
@RunWith(SpringRunner.class)
@Import(AnnotationAwareAspectJAutoProxyCreator.class) // activate aspect
@WebMvcTest(MyController.class)
public class MyControllerTest {
...
}
您必须将@EnableAspectJAutoProxy 与使用@Aspect 声明bean 的文件@Configuration 放在一起。
@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;
}
}
我认为这将完成工作。
我使用 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 引导演示应用程序将通过 CommandLineRunner
接口的 run
方法调用 sayHello
。
@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
注释和 jupiter 的测试。
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 引导中测试方面吗?
您需要开始 @SpringBootApplication
。但是,它不一定是您用来在生产环境中启动应用程序的那个。它可以是仅用于此测试的特殊版本,并且可以在您的测试源根目录中而不是您的 src 中。
@SpringBootApplication
@ComponentScan(basePackageClasses = {DemoComponent.class, TimeLoggerAspect.class})
public class SpringBootTestMain {
public static void main(String[] args) {
SpringApplication.run(SpringBootTestMain.class, args);
}
}
那么在您的测试中,这是您唯一需要列出的 class。
@ExtendWith(SpringExtension.class)
@SpringBootTest(classes = SpringBootTestMain.class)
public class DemoComponentFailTest {
另一个似乎有效的解决方案是在 @SpringBootTest
的 classes
中添加 AnnotationAwareAspectJAutoProxyCreator
,尽管我不太确定为什么。
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();
}
}
我有类似的问题。我的方面正在监听控制器方法。要激活它,导入 AnnotationAwareAspectJAutoProxyCreator
就可以了:
@RunWith(SpringRunner.class)
@Import(AnnotationAwareAspectJAutoProxyCreator.class) // activate aspect
@WebMvcTest(MyController.class)
public class MyControllerTest {
...
}
您必须将@EnableAspectJAutoProxy 与使用@Aspect 声明bean 的文件@Configuration 放在一起。
@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;
}
}
我认为这将完成工作。