gpt4 book ai didi

unit-testing - 使用 Liquibase 为 Spring Boot 应用程序中的单元测试初始化​​内存中的 H2

转载 作者:行者123 更新时间:2023-12-03 15:07:10 26 4
gpt4 key购买 nike

我在 Spring JPA 测试中多次使用 in-mem 数据库,从来没有遇到过问题。这一次,我有一个更复杂的架构要初始化,并且该架构必须有一个自定义名称(我们域模型中的一些实体与特定的目录名称相关联。)因此,出于这个原因,以及确保测试完全同步并与我们初始化和维护模式的方式一致,我试图在我的 Spring Data JPA 存储库单元测试执行之前使用 Liquibase 初始化一个内存中的 H2 数据库。

(注意:我们使用 Spring Boot 2.1.3.RELEASE MySql 作为我们的主库, H2 仅用于测试 6790 )

我一直在遵循 Spring 引用指南来设置 Liquibase executions on startup 。我的 Maven POM 中有以下条目:

 <dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.liquibase</groupId>
<artifactId>liquibase-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-test-autoconfigure</artifactId>
<scope>test</scope>
</dependency>

我的测试文件如下所示:
 @RunWith(SpringRunner.class)
@ContextConfiguration(classes = PersistenceTestConfig.class)
@DataJpaTest
public class MyRepositoryTest {

@Autowired
private MyRepository myRepository;

@Test
public void someDataAccessTest() {
// myRepository method invocation and asserts here...
// ...
}
}

应用上下文类:
  @EnableJpaRepositories({"com.mycompany.myproject"})
@EntityScan({"com.mycompany.myproject"})
public class PersistenceTestConfig {

public static void main(String... args) {
SpringApplication.run(PersistenceTestConfig.class, args);
}
}

根据引用指南,

By default, Liquibase autowires the (@Primary) DataSource in your context and uses that for migrations. If you need to use a different DataSource, you can create one and mark its @Bean as @LiquibaseDataSource. If you do so and you want two data sources, remember to create another one and mark it as @Primary. Alternatively, you can use Liquibase’s native DataSource by setting spring.liquibase.[url,user,password] in external properties. Setting either spring.liquibase.url or spring.liquibase.user is sufficient to cause Liquibase to use its own DataSource. If any of the three properties has not be set, the value of its equivalent spring.datasource property will be used.



显然,我希望我的测试使用与 Liquibase 用于初始化数据库的数据源实例相同的数据源实例。所以,起初,我试图指定 spring.datasource 属性而不提供 spring.liquibase。 [url, user, password] 属性 - 假设 Liquibase 将使用默认的主要 Spring 数据源:
spring.datasource.url=jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1;INIT=CREATE SCHEMA IF NOT EXISTS corp
spring.datasource.username=sa
spring.datasource.password=

spring.jpa.hibernate.ddl-auto=validate

# LIQUIBASE (LiquibaseProperties)
spring.liquibase.change-log=classpath:db.changelog.xml
#spring.liquibase.url=jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1;INIT=CREATE SCHEMA IF NOT EXISTS corp
#spring.liquibase.user=sa
#spring.liquibase.password=
spring.liquibase.default-schema=CORP
spring.liquibase.drop-first=true

这不起作用,因为 Liquibase 没有找到 CORP 模式,其中我 must 创建了我的表:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'liquibase' defined in class path resource  [org/springframework/boot/autoconfigure/liquibase/LiquibaseAutoConfiguratio n$LiquibaseConfiguration.class]: Invocation of init method failed; nested  exception is liquibase.exception.DatabaseException:  liquibase.command.CommandExecutionException: liquibase.exception.DatabaseException: liquibase.exception.LockException: liquibase.exception.DatabaseException: Schema "CORP" not found; SQL statement:
CREATE TABLE CORP.DATABASECHANGELOGLOCK (ID INT NOT NULL, LOCKED BOOLEAN NOT NULL, LOCKGRANTED TIMESTAMP, LOCKEDBY VARCHAR(255), CONSTRAINT PK_DATABASECHANGELOGLOCK PRIMARY KEY (ID)) [90079-197] [Failed SQL: CREATE TABLE CORP.DATABASECHANGELOGLOCK (ID INT NOT NULL, LOCKED BOOLEAN NOT NULL, LOCKGRANTED TIMESTAMP, LOCKEDBY VARCHAR(255), CONSTRAINT PK_DATABASECHANGELOGLOCK PRIMARY KEY (ID))]

所以,我去掉了明确的 spring.datasource 属性定义,只提供了以下 Liquibase 属性:
 spring.jpa.hibernate.ddl-auto=validate

# LIQUIBASE (LiquibaseProperties)
spring.liquibase.change-log=classpath:db.changelog.xml
spring.liquibase.url=jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1;INIT=CREATE SCHEMA IF NOT EXISTS corp
spring.liquibase.user=sa
spring.liquibase.password=
spring.liquibase.default-schema=CORP
spring.liquibase.drop-first=true

这导致 Liquibase 任务成功执行,并且似乎在启动时将所有必要的表和数据加载到其 native 数据源中 - 使用提供的更改日志文件。我知道发生这种情况是因为我已经明确设置了 Liquibase DS 属性,并且根据 Spring 文档,这会导致 Liquibase 使用它自己的 native 数据源。我想,出于这个原因,虽然 Liquibase 作业现在成功运行,但测试仍在尝试使用不同的 [Spring 默认?] 数据源,并且数据库模式未通过预测试验证。 (没有找到“corp”模式,没有表。)所以,很明显,测试使用的数据源实例与我尝试使用 Liquibase 生成的数据源实例不同。

如何使用 Liquibase 生成的测试进行测试?

我尝试的任何东西似乎都不起作用。我怀疑我使用的自动配置和显式配置之间存在某种冲突。在这种情况下, @DataJpaTest 是一个好方法。我确实想将我的应用程序上下文配置限制为严格的 JPA 测试,这些测试不需要任何其他内容。

它应该很简单......但是我一直无法找到正确的方法,而且我找不到任何可以清楚解释如何解决这个问题的文档。

任何帮助深表感谢!

最佳答案

问题出在@DataJpaTest您正在使用。
Documentation of @DataJpaTest

By default, tests annotated with @DataJpaTest will use an embedded in-memory database (replacing any explicit or usually auto-configured DataSource). The @AutoConfigureTestDatabase annotation can be used to override these settings.



这意味着您的自动配置的数据源被覆盖,并且 url spring.datasource.url=jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1;INIT=CREATE SCHEMA IF NOT EXISTS corp不考虑

你会在日志中找到类似的东西
EmbeddedDataSourceBeanFactoryPostProcessor : Replacing 'dataSource' DataSource bean with embedded version

要修复,请使用:
spring.test.database.replace=none

关于unit-testing - 使用 Liquibase 为 Spring Boot 应用程序中的单元测试初始化​​内存中的 H2,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57153091/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com