全部学科
Python全栈
python
NodeJS全栈
nodejs
📅 2026-05-18 6 分钟 ✍️ juanwangdev

Spring Boot 自定义Starter测试

自定义Starter需编写测试验证自动配置正确生效。

测试依赖

XML
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>

ApplicationContextRunner

Java
class MyAutoConfigurationTest {

    private final ApplicationContextRunner contextRunner =
        new ApplicationContextRunner()
            .withConfiguration(AutoConfigurations.of(MyAutoConfiguration.class));

    @Test
    void defaultServiceCreated() {
        contextRunner.run(context -> {
            assertThat(context).hasSingleBean(MyService.class);
            assertThat(context.getBean(MyService.class).getName())
                .isEqualTo("default");
        });
    }

    @Test
    void serviceNotCreatedWhenDisabled() {
        contextRunner
            .withPropertyValues("my.service.enabled=false")
            .run(context -> {
                assertThat(context).doesNotHaveBean(MyService.class);
            });
    }
}

条件注解测试

测试@ConditionalOnClass

Java
@Test
void serviceCreatedWhenClassPresent() {
    contextRunner
        .withClassLoader(new FilteredClassLoader(MyService.class))
        .run(context -> {
            assertThat(context).doesNotHaveBean(MyService.class);
        });
}

@Test
void serviceNotCreatedWhenClassMissing() {
    contextRunner
        .withClassLoader(new FilteredClassLoader())
        .run(context -> {
            assertThat(context).doesNotHaveBean(MyService.class);
        });
}

测试@ConditionalOnBean

Java
@Test
void serviceCreatedWhenDependencyBeanPresent() {
    contextRunner
        .withBean(DataSource.class, () -> new MockDataSource())
        .run(context -> {
            assertThat(context).hasSingleBean(MyService.class);
        });
}

@Test
void serviceNotCreatedWhenDependencyBeanMissing() {
    contextRunner.run(context -> {
        assertThat(context).doesNotHaveBean(MyService.class);
    });
}

配置属性测试

Java
class MyPropertiesTest {

    private final ApplicationContextRunner contextRunner =
        new ApplicationContextRunner()
            .withConfiguration(AutoConfigurations.of(MyAutoConfiguration.class))
            .withUserConfiguration(MyPropertiesTestConfiguration.class);

    @Test
    void propertiesBoundCorrectly() {
        contextRunner
            .withPropertyValues(
                "my.service.name=test-name",
                "my.service.timeout=5000"
            )
            .run(context -> {
                MyProperties properties = context.getBean(MyProperties.class);
                assertThat(properties.getName()).isEqualTo("test-name");
                assertThat(properties.getTimeout()).isEqualTo(5000);
            });
    }

    @Test
    void defaultValuesApplied() {
        contextRunner.run(context -> {
            MyProperties properties = context.getBean(MyProperties.class);
            assertThat(properties.getName()).isEqualTo("default");
            assertThat(properties.getTimeout()).isEqualTo(3000);
        });
    }
}

Web环境测试

Java
private final WebApplicationContextRunner webContextRunner =
    new WebApplicationContextRunner(
        WebApplicationContextRunner.WebType.SERVLET)
        .withConfiguration(AutoConfigurations.of(MyWebAutoConfiguration.class));

@Test
void webConfigurationCreatedInWebEnvironment() {
    webContextRunner.run(context -> {
        assertThat(context).hasSingleBean(MyWebConfiguration.class);
    });
}

测试用户覆盖

Java
@Test
void userBeanOverridesDefaultBean() {
    contextRunner
        .withBean(MyService.class, () -> new CustomMyService())
        .run(context -> {
            assertThat(context).hasSingleBean(MyService.class);
            assertThat(context.getBean(MyService.class))
                .isInstanceOf(CustomMyService.class);
        });
}

自动配置报告验证

Java
@Test
void autoConfigurationReportAvailable() {
    contextRunner
        .withPropertyValues("debug=true")
        .run(context -> {
            ConditionEvaluationReport report =
                context.getBean(ConditionEvaluationReport.class);
            assertThat(report.getConditionAndOutcomesBySource())
                .containsKey(MyAutoConfiguration.class.getName());
        });
}

集成测试示例

Java
@SpringBootTest
@EnableAutoConfiguration
@Import(MyAutoConfiguration.class)
class MyAutoConfigurationIntegrationTest {

    @Autowired(required = false)
    private MyService myService;

    @Test
    void serviceAutoConfigured() {
        assertThat(myService).isNotNull();
    }
}

测试最佳实践

实践说明
使用ApplicationContextRunner独立控制测试上下文
测试默认行为验证开箱即用
测试条件注解确认生效条件正确
测试用户覆盖确认@ConditionalOnMissingBean工作
测试配置属性验证绑定正确
测试Bean存在/不存在核心验证点

要点总结

  • ApplicationContextRunner控制测试上下文配置
  • withPropertyValues设置配置属性
  • FilteredClassLoader模拟类不存在
  • 验证条件注解生效场景
  • 测试用户自定义Bean覆盖能力
  • 组合测试覆盖各种配置场景
想在手机上练习这篇文章的配套题目?
使用微信卷王开发者小程序,打开首页顶部扫码功能识别二维码
← 上一篇 Spring Boot spring.factories配置
下一篇 → Spring Boot @Enable注解与@Import原理
扫码体验小程序
加载中
想在手机上刷题学习?
使用微信卷王开发者小程序,打开首页顶部扫码功能识别二维码