【问题标题】:Dynamically creating schema.sql before Spring context在 Spring 上下文之前动态创建 schema.sql
【发布时间】:2018-09-25 21:54:34
【问题描述】:

我正在为项目编写集成测试,我想在 Spring 选择它来填充数据库之前将所有数据库迁移脚本合并到 schema.sql 中。 为此,我使用了一个小类,它在项目中搜索 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 并让我的类生成它,那么它会如所描述的那样失败。 我试图在 SpringJUnit4ClassRunner 中覆盖 run(RunNotifier notifier) 方法并将我的迁移合并放在那里,然后它调用 super.run(notifier) 方法,但这仍然不起作用。 有没有办法在 Spring 得到它之前生成 schema.sql?

附: 我不能将 flyway 用于生产环境。或许可以仅将其用于测试?

更新: 经过一些实验,我在 test.yml 中设置了这个:

spring.jpa.hibernate.ddl-auto: none

现在它加载上下文,执行一项仅获取 Oauth2 令牌的测试,并在执行 POST 和 GET 请求的其他测试中失败,因为它无法执行在测试方法之前放置额外数据的 @sql 注释。数据库似乎没有受到任何影响,即没有任何表。

【问题讨论】:

    标签: java spring-boot integration-testing


    【解决方案1】:

    您可以通过使用 @TestPropertySource(properties = {"spring.flyway.enabled=true"}) 注释或使用其自己的属性文件创建 test Spring 配置文件来仅为测试启用 flyway。后者看起来像:

    @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 中已重命名。

    【讨论】:

    • 看起来这需要对我的情况进行大量更改。我有@ActiveProfiles(resolver = CustomActiveProfileResolver.class),一旦我将flyway-test依赖添加到POM,它就会开始生成错误。
    【解决方案2】:

    也许有人会觉得这很有用。 我设法通过使用带有故障安全插件的 exec-maven-plugin 来解决这个问题。 测试类设置保持不变,我只从 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 类具有 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 并自动设置数据库地址。

    【讨论】:

      猜你喜欢
      • 2017-06-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-08-23
      • 1970-01-01
      • 2020-08-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多