Reputation: 1684
I'm trying to execute some SQL statements with @SqlGroup before running some integration tests using Spring 5, Junit4.11 and JDK8.
Everything was working flawless until today, when I added some initial configuration on my "ConfigurationComponent" bean, with the annotation @PostConstruct.
As @PostConstruct method calls a database-dependent bean, the test fails, because hiberante (thus the database) can't find the preloaded schema.
As I investigated, I found that statements put in @SqlGroup will execute after ApplicationContext initialization, so the @PostConstruct is executed before the schema is loaded.
Here is my integration test abstract class.
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath:application-context-test.xml" })
@Transactional
@Rollback(true)
@SqlGroup({
@Sql(executionPhase = ExecutionPhase.BEFORE_TEST_METHOD, scripts = {
"classpath:db_config.sql",
"classpath:consultas/setup_esquema_0.1.sql",
"classpath:db_datos_iniciales.sql"}),
@Sql(executionPhase = ExecutionPhase.AFTER_TEST_METHOD, scripts = "classpath:db_teardown.sql") })
public abstract class AbstractServiceTest {
@BeforeClass
public static void setUpBeforeClass() throws Exception {
}
@AfterClass
public static void tearDownAfterClass() throws Exception {
}
@Before
public abstract void setUp() throws Exception;
@After
public abstract void tearDown() throws Exception;
public static Long randomId() {
return new Long(Math.round(Math.random() * 1000));
}
}
The offending bean
@Configuration
public class ConfigurationComponent {
@Autowired
Resources resources; // resources are retrieved from database.
@PostConstruct
public void startUp() throws VariableGlobalInexistenteException {
Config.environment = resources
.getWsaaEnv();
Config.validation = resources
.getWsaaEnvValidation();
}
}
I can't find a way to overcome this issue using @SqlGroup. Is there any solution, a way to alter the lifecycle and execute the sql statements first?.
As you can see, I'm using ExecutionPhase.BEFORE_TEST_METHOD
, there is no
explicit configuration for this case, like "ExecutionPhase.BEFORE_SETUP".
Update 09-07-2018 - Looks like there is no way of achieving this using @Sql:
Both @Sql and the calling of @PostConstruct are handled by Spring Framework rather than Spring Boot. Also, I believe this is working as designed. The default execution phase for @Sql is BEFORE_TEST_METHOD (the other option is AFTER_TEST_METHOD). The application context is refreshed, and therefore @PostConstruct is called, once for the whole test class (in fact it could be once for multiple test classes if they share the same configuration) which happens before individual test methods are called. In other words, you cannot use @Sql as a means of preparing the database for calls that are made in @PostConstruct.
Github @PostConstruct executed before @Sql
Upvotes: 3
Views: 2625
Reputation: 418
Another workaround would be implementing CommandLineRunner.
@Component
public class ConfigurationInitRunner implements CommandLineRunner {
@Autowired
Resources resources; // resources are retrieved from database.
@Override
public void run(String... strings) throws Exception {
Config.environment = resources.getWsaaEnv();
Config.validation = resources.getWsaaEnvValidation();
}
}
Upvotes: 1
Reputation: 1684
I've managed to find a workaround. As the latest update stated, there is no way of achieving the desired behavior using @SqlGroup. I've had to use the following approach, using @BeforeClass and @AfterClass:
@BeforeClass
public static void setUpBeforeClass() throws Exception {
DriverManagerDataSource dataSource = getDataSource();
Connection conn = dataSource.getConnection();
ScriptUtils.executeSqlScript(conn, new ClassPathResource("db_config.sql"));
ScriptUtils.executeSqlScript(conn, new ClassPathResource("consultas/setup_schema"));
ScriptUtils.executeSqlScript(conn, new ClassPathResource("db_init.sql"));
JdbcUtils.closeConnection(conn);
}
@AfterClass
public static void tearDownAfterClass() throws Exception {
Connection conn = getDataSource().getConnection();
ScriptUtils.executeSqlScript(conn, new ClassPathResource(
"db_teardown.sql"));
JdbcUtils.closeConnection(conn);
}
private static DriverManagerDataSource getDataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setUrl(url);
dataSource.setUsername(username);
dataSource.setPassword(password);
dataSource.setDriverClassName(driver);
return dataSource;
}
All @SqlGroup annotations were removed. This methodology is quite clean, as ScriptUtils doesn't need much dependencies to run.
Upvotes: 1