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 befor
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);
}
You can use JUnit 5's @BeforeAll annotation
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
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