How to populate database only once before @Test methods in spring test?

Example based on Mike Adlers example but for JUnit 5 and with use of ResourceDatabasePopulator mentioned by Tugdual.

Test classes is created once for every test method. So if you want to populate only once you need to handle that somehow. Here it is done with a static variable.

@Autowired
private DataSource dataSource;

private static boolean isInitialized;

@BeforeEach // JUnit 5
void initDatabase() {
  if(!isInitialized) { // init only once
    ResourceDatabasePopulator populator = new ResourceDatabasePopulator();
    populator.addScript(new ClassPathResource("/sql/myscript.sql")));
    populator.execute(dataSource);
    isInitialized = true;
  }
}

Edited: A Better solution.

Junit 5 provides @BeforeAll as mentioned by others and should be the correct answer

@Autowired
private DataSource dataSource;

@BeforeAll // JUnit 5
void initDatabase() {
  ResourceDatabasePopulator populator = new ResourceDatabasePopulator();
  populator.addScript(new ClassPathResource("/sql/myscript.sql")));
  populator.execute(dataSource);
}

Building on Alfredos answer, this is a way to inject database information without calling the embedded database's default script. For instance, this may be useful when you want to automagically build the DDL for you - at least in tests.

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({"/applicationContext.xml"})
public class TestClass {

    @Autowired
    private ApplicationContext ctx;

    private JdbcTemplate template;

    @Autowired
    public void setDataSource(DataSource dataSource) {
       template = new JdbcTemplate(dataSource);
    }

    private static boolean isInitialized = false;

    @Before
    public void runOnce() {
        if (isInitialized) return;
        System.out.println("Initializing database");

        String script = "classpath:script.sql"; 
        Resource resource = ctx.getResource(script);
        JdbcTestUtils.executeSqlScript(template, resource, true);            
        isInitialized = true;
    }
}

This way, the runOnce() method is called once and only once for the test run. If you make isInitialized an instance field (non-static), the method will be called before every test. This way you can drop/repopulate the tables, if necessary, before every test run.

Note that this is still a rather quick-and-dirty solution and the sensible way to handle the database is in accordance with Ralph's answer.


in case you are spring boot, u can mention multiple scripts to launch before tests via

spring.datasource.data=classpath:accounts.sql, classpath:books.sql, classpath:reviews.sql

Use Springs Embedded Database Support

<jdbc:embedded-database id="dataSource">
    <jdbc:script location="classpath:myScript.sql"/>
    <jdbc:script location="classpath:otherScript.sql"/>
</jdbc:embedded-database>

or Springs Initialize Database Support

<jdbc:initialize-database data-source="dataSource">
    <jdbc:script location="classpath:myScript.sql"/>
    <jdbc:script location="classpath:otherScript.sql"/>
</jdbc:initialize-database>

@See http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/jdbc.html#jdbc-embedded-database-support