How can I tell the @Sql
annotation to run only once for the class, and not for each @Test
method?
Like having the same behaviour as @BeforeClass
?
@org.springframework.test.context.jdbc.Sql(
scripts = "classpath:schema-test.sql",
executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD
)
public class TestClass {
@Test
public void test1() {
//runs the @Sql script
}
@Test
public void test2() {
//runs the @Sql script again
}
}
Again, very similar to the @DataJpaTest and the @DataMongoTest annotations, to perform classic Spring MVC tests, we apply the @WebMvcTest annotation alongside the @RunWith(SpringRunner. class) annotation. Keep in mind that the effects of this annotation only apply to the MVC infrastructure.
The core items for the testing are contained in the modules called spring-boot-test and the configuration is provided by the modules called spring-boot-test-autoconfigure. We can simply use the spring-boot-starter-test in pom. xml and transitively pull all the required dependencies in a Spring application.
We do this using JUnit's @RunWith annotation. We also annotate our test class with Spring's @ContextConfiguration annotation without specifying any attributes.
For JUnit 5, the straight forward clean solution:
@MyInMemoryDbConfig
//@Sql(value = {"/appconfig.sql", "/album.sql"}) -> code below is equivalent but at class level
class SomeServiceTest {
@BeforeAll
void setup(@Autowired DataSource dataSource) {
try (Connection conn = dataSource.getConnection()) {
// you'll have to make sure conn.autoCommit = true (default for e.g. H2)
// e.g. url=jdbc:h2:mem:myDb;DB_CLOSE_DELAY=-1;MODE=MySQL
ScriptUtils.executeSqlScript(conn, new ClassPathResource("appconfig.sql"));
ScriptUtils.executeSqlScript(conn, new ClassPathResource("album.sql"));
}
}
// your @Test methods follow ...
but when your database connections are not configured with autoCommit = true
you'll have to wrap all in a transaction:
@RootInMemoryDbConfig
@Slf4j
class SomeServiceTest {
@BeforeAll
void setup(@Autowired DataSource dataSource,
@Autowired PlatformTransactionManager transactionManager) {
new TransactionTemplate(transactionManager).execute((ts) -> {
try (Connection conn = dataSource.getConnection()) {
ScriptUtils.executeSqlScript(conn, new ClassPathResource("appconfig.sql"));
ScriptUtils.executeSqlScript(conn, new ClassPathResource("album.sql"));
// should work without manually commit but didn't for me (because of using AUTOCOMMIT=OFF)
// I use url=jdbc:h2:mem:myDb;DB_CLOSE_DELAY=-1;MODE=MySQL;AUTOCOMMIT=OFF
// same will happen with DataSourceInitializer & DatabasePopulator (at least with this setup)
conn.commit();
} catch (SQLException e) {
SomeServiceTest.log.error(e.getMessage(), e);
}
return null;
});
}
// your @Test methods follow ...
Why clean solution?
Because according to Script Configuration with @SqlConfig:
The configuration options provided by @Sql and @SqlConfig are equivalent to those supported by ScriptUtils and ResourceDatabasePopulator but are a superset of those provided by the XML namespace element.
Bonus
You can mix this approach with other @Sql declarations.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With