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

2022-10-06  本文已影响0人  伊丽莎白2015

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,我们可以写如下的测试类:

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));
    }
}
上一篇下一篇

猜你喜欢

热点阅读