Question

My next problem testing spring service layer with junit4 is: How to call script that populates database only once before all @Test methods: I want to execute this once before all @Tests:

JdbcTestUtils.executeSqlScript(jdbcTemplate(), new FileSystemResource(
"src/main/resources/sql/mysql/javahelp-insert.sql"), false);

I tried to use @PostConstruct on my GenericServiceTest class(extended by test classes). It turned out that @PostConstruct is called every time before every @Test method. Interesting is that even methods annotated @Autowired of GenericServiceTest are called before every @Test method.

I don't want to populate database before every test class but only once at spring-test startup.

How to execute above method only once before all @Test methods with spring testing framework and junit4?

Thank you!

Was it helpful?

Solution 2

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

OTHER TIPS

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.

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);
}

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

You can use JUnit 5's @BeforeAll annotation

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top