@SpringBootTest 需要数据库连接?
Posted
技术标签:
【中文标题】@SpringBootTest 需要数据库连接?【英文标题】:@SpringBootTest requiring database connection? 【发布时间】:2021-11-27 12:28:46 【问题描述】:我有一些集成测试,为此我使用了 Testcontainers。但是我突然意识到,当我的 docker 容器和我的应用程序的数据库关闭时,所有其他测试(不包括使用 Testcontainers 的集成测试)都失败了(甚至是 Spring Boot initializr 生成的contextLoads()
测试)
我明白了:
java.lang.IllegalStateException: 无法加载 ApplicationContext 在 org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:132)
引起:org.springframework.beans.factory.BeanCreationException: 在类路径中定义名称为“liquibase”的 bean 创建错误 资源
[org/springframework/boot/autoconfigure/liquibase/LiquibaseAutoConfiguration$LiquibaseConfiguration.class]: 调用 init 方法失败;嵌套异常是 liquibase.exception.DatabaseException: com.mysql.cj.jdbc.exceptions.CommunicationsException:通信 链接失败
很明显,应用要连接数据库,数据库容器宕机了。
我一直在调查,但我不记得曾经需要为应用程序的测试/构建过程启动容器,所以这个问题对我来说是新问题。但如果有什么地方做错了,它可能就在这里,在我的AbstractDatabaseIT
类中:
@ActiveProfiles("test")
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
@ContextConfiguration(initializers = AbstractDatabaseIT.DockerMySqlDataSourceInitializer.class)
@Testcontainers
public abstract class AbstractDatabaseIT
private static final String MYSQL_IMAGE_NAME = "mysql:5.7.24";
public static final MySQLContainer<?> mySQLContainer = new MySQLContainer<>(MYSQL_IMAGE_NAME);
static
mySQLContainer.start();
public static class DockerMySqlDataSourceInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext>
@Override
public void initialize(@NotNull ConfigurableApplicationContext applicationContext)
Map<String, String> parameters = new HashMap<>();
parameters.put("command", "--character-set-server=utf8");
TestPropertySourceUtils.addInlinedPropertiesToEnvironment(
applicationContext,
"spring.datasource.url=" + mySQLContainer.getJdbcUrl(),
"spring.datasource.username=" + mySQLContainer.getUsername(),
"spring.datasource.password=" + mySQLContainer.getPassword()
);
mySQLContainer.setParameters(parameters);
集成测试扩展了这个类:
public class ChallengeIT extends AbstractDatabaseIT
@Autowired
private ChallengeRepository repository;
// tests here
所有其他非集成类都有@SpringBootTest
注解,以及使用@Autowired注入的依赖项(也许这是这里的问题?)
@SpringBootTest
class EthMessageVerifierTest
@Autowired
private EthMessageVerifier ethMessageVerifier;
// tests here
我在这里缺少什么?我记得在许多项目中都看到了 H2 数据库依赖项。我应该放弃测试容器以支持 H2 吗?或者我可以以某种方式为所有其他测试创建一个测试容器实例吗?
【问题讨论】:
【参考方案1】:使用@SpringBootTest
注释的测试尝试填充整个 Spring 上下文。这包括您的所有 bean:您的 Web 层、您的业务逻辑、您的数据库设置等。
因此,运行整个应用程序所需的所有基础设施(例如消息队列、远程系统、数据库)也需要用于此类测试。
所以@SpringBootTest
也表示集成测试,您需要在应用程序启动时提供数据库设置,Spring Boot 的自动配置会尝试配置您的DataSource
。
有关更多信息,请考虑此article on @SpringBootTest 和此一般overview about unit & integration testing with Spring Boot。您不必总是使用@SpringBootTest
,也可以使用 Spring Boots many test slice annotations 之一来单独测试某些东西。
【讨论】:
以上是关于@SpringBootTest 需要数据库连接?的主要内容,如果未能解决你的问题,请参考以下文章
从“@WebFluxTest”迁移到“@SpringBootTest”后,集成测试中的连接被拒绝
找不到@SpringBootConfiguration,您需要在测试中使用@ContextConfiguration 或@SpringBootTest(classes=...)
SpringBootTest、Testcontainers、容器启动——映射端口只能在容器启动后获取