Populate a database with TestContainers in a SpringBoot integration test

前端 未结 6 1891
自闭症患者
自闭症患者 2021-02-20 07:10

I am testing TestContainers and I would like to know how to populate a database executing a .sql file to create the structure and add some rows.

How to do it?

         


        
6条回答
  •  囚心锁ツ
    2021-02-20 08:00

    The easiest way is to use JdbcDatabaseContainer::withInitScript

    Advantage of this solution is that script is run before Spring Application Context loads (at least when it is in a static block) and the code is quite simple.

    Example:

    static {
        postgreSQLContainer = new PostgreSQLContainer("postgres:9.6.8")
                .withDatabaseName("integration-tests-db")
                .withUsername("sa")
                .withPassword("sa");
        postgreSQLContainer
                .withInitScript("some/location/on/classpath/someScript.sql");
        postgreSQLContainer.start();
    }
    

    JdbcDatabaseContainer is superclass of PostgreSQLContainer so this solution should work not only for postgres, but also for other containers.

    If you want to run multiple scripts you can do it in a similar manner

    Example:

    static {
        postgreSQLContainer = new PostgreSQLContainer("postgres:9.6.8")
                .withDatabaseName("integration-tests-db")
                .withUsername("sa")
                .withPassword("sa");
        postgreSQLContainer.start();
    
        var containerDelegate = new JdbcDatabaseDelegate(postgreSQLContainer, "");
    
         ScriptUtils.runInitScript(containerDelegate, "some/location/on/classpath/someScriptFirst.sql");
         ScriptUtils.runInitScript(containerDelegate, "some/location/on/classpath/someScriptSecond.sql");
         ScriptUtils.runInitScript(containerDelegate, "ssome/location/on/classpath/someScriptThird.sql");
    }
    

    There are also other options

    Spring Test @Sql annotation

    @SpringBootTest
    @Sql("some/location/on/classpath/someScriptFirst.sql", "some/location/on/classpath/someScriptSecond.sql")
    public class SomeTest {
        //...
    }
    

    ResourceDatabasePopulator from jdbc.datasource.init or r2dbc.connection.init when using JDBC or R2DBC consecutively

    class DbInitializer {
        private static boolean initialized = false;
    
        @Autowired
        void initializeDb(ConnectionFactory connectionFactory) {
            if (!initialized) {
                ResourceLoader resourceLoader = new DefaultResourceLoader();
                Resource[] scripts = new Resource[] {
                        resourceLoader.getResource("classpath:some/location/on/classpath/someScriptFirst.sql"),
                        resourceLoader.getResource("classpath:some/location/on/classpath/someScriptSecond.sql"),
                        resourceLoader.getResource("classpath:some/location/on/classpath/someScriptThird.sql")
                };
                new ResourceDatabasePopulator(scripts).populate(connectionFactory).block();
                initialized = true;
            }
        }
    }
    
    @SpringBootTest
    @Import(DbInitializer.class)
    public class SomeTest {
        //...
    }
    

    Init script in database URI when using JDBC

    It is mentioned in offical Testcontainers documentation:
    https://www.testcontainers.org/modules/databases/jdbc/

    Classpath file:
    jdbc:tc:postgresql:9.6.8:///databasename?TC_INITSCRIPT=somepath/init_mysql.sql

    File that is not on classpath, but its path is relative to the working directory, which will usually be the project root:
    jdbc:tc:postgresql:9.6.8:///databasename?TC_INITSCRIPT=file:src/main/resources/init_mysql.sql

    Using an init function:
    jdbc:tc:postgresql:9.6.8:///databasename?TC_INITFUNCTION=org.testcontainers.jdbc.JDBCDriverTest::sampleInitFunction

    package org.testcontainers.jdbc;
    
    public class JDBCDriverTest {
        public static void sampleInitFunction(Connection connection) throws SQLException {
            // e.g. run schema setup or Flyway/liquibase/etc DB migrations here...
        }
        ...
    }
    

提交回复
热议问题