在 Spring 上下文之前动态创建 schema.sql
Dynamically creating schema.sql before Spring context
我正在为项目编写集成测试,我想在 Spring 选择它来填充数据库之前将所有数据库迁移脚本合并到 schema.sql 中。
为此,我使用一个小的 class 在项目中搜索 sql 文件并将它们合并为一个。
我创建了一个这样的套件:
@RunWith(Suite.class)
@Suite.SuiteClasses({MyTests.class})
public class SuiteTest {
@BeforeClass
public static void setUp() throws IOException {
RunMigrations.mergeMigrations();//this one merges all sqls into one file, called schema.sql
}
}
那么,这是我的测试:
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = App.class)
@ActiveProfiles(resolver = CustomActiveProfileResolver.class)
@ContextConfiguration(classes = App.class)
public class MyTests extends AbstractTransactionalJUnit4SpringContextTests {
@PostConstruct
public void before() {
mvc = MockMvcBuilders.webAppContextSetup(context).addFilter(springSecurityFilterChain).build();
}
@Test
@Transactional
public void Test1(){ //do stuff }
}
但这并不像我想象的那样有效。看起来 Spring 尝试 运行 schema.sql 比我创建它的速度更快,但失败了:
Caused by: org.hibernate.tool.schema.spi.SchemaManagementException: Schema-validation: missing table [application]
如果我只是关闭生成 schema.sql 的代码并让 Spring 运行 使用已创建的架构,那么一切都很好。但是,如果我删除 schema.sql 并让我的 class 生成它,那么它就会像描述的那样失败。
我试图在 SpringJUnit4ClassRunner 中覆盖 运行(RunNotifier notifier) 方法并将我的迁移合并放在那里,然后再调用 super.run(notifier) 方法,但这仍然没有工作。
有没有办法在 Spring 得到它之前生成 schema.sql?
P.S。
我不能将 flyway 用于生产环境。也许仅用于测试是可能的?
更新:
经过一些试验,我将其设置为 test.yml:
spring.jpa.hibernate.ddl-auto: none
现在它加载上下文,执行一个只获取 Oauth2 令牌的测试,并在执行 POST 和 GET 请求的其他测试中失败,因为它无法执行在测试之前放置额外数据的 @sql 注释方法。数据库似乎未受影响,即没有任何表格。
您可以通过使用 @TestPropertySource(properties = {"spring.flyway.enabled=true"})
注释或使用自己的 属性 文件创建 test
Spring 配置文件来仅为测试启用飞路。后者看起来像:
@RunWith(SpringRunner.class)
@SpringBootTest
@ActiveProfiles("test")
public MyTest {
与 src/test/resources/application-test.yml
文件:
spring:
flyway:
enabled: true
和 flyway-core
作为测试范围的依赖项。
请注意,Spring Boot 中的 Flyway 属性在 Spring Boot 2.0 中已重命名。
也许有人会觉得这很有用。
我设法通过使用带有故障安全插件的 exec-maven-plugin 来解决这个问题。
测试 class 设置保持不变,我只是从 Suite 中删除了 @BeforeClass 注释。
这是 POM:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>${org.apache.maven.plugins.maven-surefire-plugin-version}</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>${org.apache.maven.plugins.maven-failsafe-plugin-version}</version>
<executions>
<execution>
<id>integration-test-for-postgres</id>
<phase>integration-test</phase>
<goals>
<goal>integration-test</goal>
</goals>
</execution>
<execution>
<id>verify-for-postgres</id>
<phase>verify</phase>
<goals>
<goal>verify</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>${org.codehaus.mojo.exec-maven-plugin-version}</version>
<executions>
<execution>
<id>build-test-environment</id>
<phase>generate-test-resources</phase>
<goals>
<goal>java</goal>
</goals>
</execution>
</executions>
<configuration>
<!--This class prepares the schema.sql file which is fed to Spring to init DB before tests.-->
<mainClass>...GenerateTestDBSchema</mainClass>
<arguments>
<argument>...</argument><!--the migration folder-->
<argument>...</argument><!--The path where to put schema sql-->
</arguments>
</configuration>
</plugin>
</plugins>
</build>
GenerateTestDBSchema class 具有 main 方法并使用 args 数组接受查找迁移和放置的路径 schema.sql。
public static void main(String[] args) {
try {
mergeMigrations(args[0], args[1]);
} catch (IOException e) {
LOG.error(e.getMessage());
}
}
mergeMigrations() 方法很简单:只需从目录中取出所有文件,合并它们并写入输出路径。这样 Spring 在上下文启动之前就有了 schema.sql 并且它自己决定 运行 迁移到哪里。
感谢@ActiveProfiles(resolver = CustomActiveProfileResolver.class) 在集成测试中,spring 解析配置文件并获取 application-{profileName}.yml 并自动设置数据库地址。
我正在为项目编写集成测试,我想在 Spring 选择它来填充数据库之前将所有数据库迁移脚本合并到 schema.sql 中。 为此,我使用一个小的 class 在项目中搜索 sql 文件并将它们合并为一个。 我创建了一个这样的套件:
@RunWith(Suite.class)
@Suite.SuiteClasses({MyTests.class})
public class SuiteTest {
@BeforeClass
public static void setUp() throws IOException {
RunMigrations.mergeMigrations();//this one merges all sqls into one file, called schema.sql
}
}
那么,这是我的测试:
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = App.class)
@ActiveProfiles(resolver = CustomActiveProfileResolver.class)
@ContextConfiguration(classes = App.class)
public class MyTests extends AbstractTransactionalJUnit4SpringContextTests {
@PostConstruct
public void before() {
mvc = MockMvcBuilders.webAppContextSetup(context).addFilter(springSecurityFilterChain).build();
}
@Test
@Transactional
public void Test1(){ //do stuff }
}
但这并不像我想象的那样有效。看起来 Spring 尝试 运行 schema.sql 比我创建它的速度更快,但失败了:
Caused by: org.hibernate.tool.schema.spi.SchemaManagementException: Schema-validation: missing table [application]
如果我只是关闭生成 schema.sql 的代码并让 Spring 运行 使用已创建的架构,那么一切都很好。但是,如果我删除 schema.sql 并让我的 class 生成它,那么它就会像描述的那样失败。 我试图在 SpringJUnit4ClassRunner 中覆盖 运行(RunNotifier notifier) 方法并将我的迁移合并放在那里,然后再调用 super.run(notifier) 方法,但这仍然没有工作。 有没有办法在 Spring 得到它之前生成 schema.sql?
P.S。 我不能将 flyway 用于生产环境。也许仅用于测试是可能的?
更新: 经过一些试验,我将其设置为 test.yml:
spring.jpa.hibernate.ddl-auto: none
现在它加载上下文,执行一个只获取 Oauth2 令牌的测试,并在执行 POST 和 GET 请求的其他测试中失败,因为它无法执行在测试之前放置额外数据的 @sql 注释方法。数据库似乎未受影响,即没有任何表格。
您可以通过使用 @TestPropertySource(properties = {"spring.flyway.enabled=true"})
注释或使用自己的 属性 文件创建 test
Spring 配置文件来仅为测试启用飞路。后者看起来像:
@RunWith(SpringRunner.class)
@SpringBootTest
@ActiveProfiles("test")
public MyTest {
与 src/test/resources/application-test.yml
文件:
spring:
flyway:
enabled: true
和 flyway-core
作为测试范围的依赖项。
请注意,Spring Boot 中的 Flyway 属性在 Spring Boot 2.0 中已重命名。
也许有人会觉得这很有用。 我设法通过使用带有故障安全插件的 exec-maven-plugin 来解决这个问题。 测试 class 设置保持不变,我只是从 Suite 中删除了 @BeforeClass 注释。 这是 POM:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>${org.apache.maven.plugins.maven-surefire-plugin-version}</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>${org.apache.maven.plugins.maven-failsafe-plugin-version}</version>
<executions>
<execution>
<id>integration-test-for-postgres</id>
<phase>integration-test</phase>
<goals>
<goal>integration-test</goal>
</goals>
</execution>
<execution>
<id>verify-for-postgres</id>
<phase>verify</phase>
<goals>
<goal>verify</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>${org.codehaus.mojo.exec-maven-plugin-version}</version>
<executions>
<execution>
<id>build-test-environment</id>
<phase>generate-test-resources</phase>
<goals>
<goal>java</goal>
</goals>
</execution>
</executions>
<configuration>
<!--This class prepares the schema.sql file which is fed to Spring to init DB before tests.-->
<mainClass>...GenerateTestDBSchema</mainClass>
<arguments>
<argument>...</argument><!--the migration folder-->
<argument>...</argument><!--The path where to put schema sql-->
</arguments>
</configuration>
</plugin>
</plugins>
</build>
GenerateTestDBSchema class 具有 main 方法并使用 args 数组接受查找迁移和放置的路径 schema.sql。
public static void main(String[] args) {
try {
mergeMigrations(args[0], args[1]);
} catch (IOException e) {
LOG.error(e.getMessage());
}
}
mergeMigrations() 方法很简单:只需从目录中取出所有文件,合并它们并写入输出路径。这样 Spring 在上下文启动之前就有了 schema.sql 并且它自己决定 运行 迁移到哪里。 感谢@ActiveProfiles(resolver = CustomActiveProfileResolver.class) 在集成测试中,spring 解析配置文件并获取 application-{profileName}.yml 并自动设置数据库地址。