美文网首页
【测试相关】如何测试Spring Boot自定义的AutoCon

【测试相关】如何测试Spring Boot自定义的AutoCon

作者: 伊丽莎白2015 | 来源:发表于2022-10-06 16:28 被阅读0次

1. 创建自己的Auto-configuration

官网文档(Creating Your Own Auto-configuration)https://docs.spring.io/spring-boot/docs/current/reference/html/features.html#features.developing-auto-configuration

更多的Auto-configuration,可以参考spring-cloud-sleuth-autoconfigure项目,它是sleuth的auto-configure模块:
https://github.com/spring-cloud/spring-cloud-sleuth/tree/3.1.x/spring-cloud-sleuth-autoconfigure

比如针对@Shcheduled的trace自动装配类:TraceSchedulingAutoConfiguration

@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(name = "org.aspectj.lang.ProceedingJoinPoint")
@ConditionalOnProperty(value = "spring.sleuth.scheduled.enabled", matchIfMissing = true)
@ConditionalOnBean(Tracer.class)
@EnableConfigurationProperties(SleuthSchedulingProperties.class)
@AutoConfigureAfter(BraveAutoConfiguration.class)
public class TraceSchedulingAutoConfiguration {
    @Bean
    TraceSchedulingAspect traceSchedulingAspect(Tracer tracer, SleuthSchedulingProperties sleuthSchedulingProperties) {
        String skipPatternString = sleuthSchedulingProperties.getSkipPattern();
        Pattern skipPattern = skipPatternString != null ? Pattern.compile(skipPatternString) : null;
        return new TraceSchedulingAspect(tracer, skipPattern);
    }
}

也可以自已写一个,当项目classpath中有javax.servlet.Filter这个类时,并且com.test.user != false时,就会自动创建bean为userStarterService:

@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(Filter.class)
@ConditionalOnProperty(value = "com.test.user", matchIfMissing = true)
public class UserAutoConfiguration {
    @Bean
    public UserStarterService userStarterService() {
        return new UserStarterService();
    }
}

2. 如何通过Unit Test测试我们的Auto-Configure类

上述我们自己的UserAutoConfiguration类,在现实中可以创建一个空的项目A,再引入这个类所在的starter包,那么运行项目A后会发现没有创建userStarterService bean。或是在项目A中application.yaml,将com.test.user置为false,同样的也不会创建userStarterService bean。

想要测试创建userStarterService bean的case,那么可以创建创目B,再引入UserAutoConfiguration所在的starter包,将引入spring-boot-starter-web(因为这个包中有Filter类),那么在启动项目B的时候,就会自动创建userStarterService bean。

上述是后期在集成中的case。但在UserAutoConfiguration所在的starter项目中,应该要有自己的关于这个类的单元测试。即如何测试Spring Boot自定义的AutoConfiguration类?

官方文档(Testing your Auto-configuration)https://docs.spring.io/spring-boot/docs/current/reference/html/features.html#features.developing-auto-configuration.testing

即使用ApplicationContextRunner类进行测试。这个类位于spring-boot-test包中。

针对主述的UserAutoConfiguration,我们可以写如下的测试类:

  • 首先需要创建ApplicationContextRunner类,并且需要告诉它总是需要加载UserAutoConfiguration.class(这里可以传入多个class)。
  • 测试方法中的Assertions不是JUnit5中的那个类,而是AspectJ中的,(因为JUnit5中的没有assertThat方法)。具体的类为:org.assertj.core.api.Assertions
  • 因为starter本身肯定是需要Filter.class类的(因为在UserAutoConfiguration有用到),那么怎么测试classpath没有Filter.class的情况呢?可以使用ApplicationContextRunner#withClassLoader重写Classpath:
    FilteredClassLoader会将传入它的类在现有的classpath中移除掉。即模拟项目中没有Filter.class类的时候,那么@ConditionalOnClass(Filter.class)不生效,即不会创建userStarterService bean。所以在verify的时候,用的是方法doesNotHaveBean
  • 同样的,ApplicationContextRunner可以模拟property value,例如使用withPropertyValues("com.test.user=false"),可以轻松的测试@ConditionalOnProperty(value = "com.test.user", matchIfMissing = true)不匹配的情况。
public class UserAutoConfigurationTest {
    private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
            .withConfiguration(AutoConfigurations.of(UserAutoConfiguration.class));

    @Test
    public void should_create_bean() {
        contextRunner.run(context -> Assertions.assertThat(context).hasSingleBean(UserStarterService.class));
    }

    @Test
    public void should_not_create_bean_as_no_filter_class() {
        contextRunner.withClassLoader(new FilteredClassLoader(Filter.class))
                .run(context -> Assertions.assertThat(context).doesNotHaveBean(UserStarterService.class));
    }

    @Test
    public void should_not_create_bean_as_property_false() {
        contextRunner.withPropertyValues("com.test.user=false")
                .run(context -> Assertions.assertThat(context).doesNotHaveBean(UserStarterService.class));
    }
}

3. 更多的sample

关于#1中引用的Spring Sleuth的TraceSchedulingAutoConfiguration类,它的测试类源码可以看 github

总体上就是我们上述介绍的方式。sleuth中还有更多的关于Auto-Configure的单元测试,可以在github中看。

import org.aspectj.lang.ProceedingJoinPoint;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;

import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.test.context.FilteredClassLoader;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.cloud.sleuth.autoconfig.TraceNoOpAutoConfiguration;
import org.springframework.cloud.sleuth.instrument.scheduling.TraceSchedulingAspect;

class TraceSchedulingAutoConfigurationTest {
    private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
            .withPropertyValues("spring.sleuth.noop.enabled=true").withConfiguration(
                    AutoConfigurations.of(TraceNoOpAutoConfiguration.class, TraceSchedulingAutoConfiguration.class));

    @Test
    void shoud_create_TraceSchedulingAspect() {
        this.contextRunner.run(context -> Assertions.assertThat(context).hasSingleBean(TraceSchedulingAspect.class));
    }

    @Test
    void shoud_not_create_TraceSchedulingAspect_without_aspectJ() {
        this.contextRunner.withClassLoader(new FilteredClassLoader(ProceedingJoinPoint.class))
                .run(context -> Assertions.assertThat(context).doesNotHaveBean(TraceSchedulingAspect.class));
    }
}

相关文章

网友评论

      本文标题:【测试相关】如何测试Spring Boot自定义的AutoCon

      本文链接:https://www.haomeiwen.com/subject/wuwmartx.html