Can anyone using DBRider / Test Container in spring boot give advice ?
I've been using DBRider/Testcontainer without any issue, but at some point , it doesn't work out.
It seesm HikariProxyPreparedStatement.execute() of DBUnit 's SimplePreparedStatement.addBatch() is being called, but could not insert any data.
Here's my test code that I've tried to verify initially.
( I've configured spring boot test code just like the example of DBRider, yet it seems like inserting the data kept failing. )
@Testcontainers
@SpringBootTest
@DBRider
@DBUnit(caseInsensitiveStrategy = Orthography.LOWERCASE)
class TestcontainersConfiguration {
@Autowired
private AdminRepository adminRepository;
@Container
static MySQLContainer<?> mySQLContainer = MySQLFixture.getInstance();
static {
JdbcDatabaseDelegate jdbcDatabaseDelegate = new JdbcDatabaseDelegate(mySQLContainer, "");
ScriptUtils.runInitScript(jdbcDatabaseDelegate,"mock/sql/admin.sql");
}
@DynamicPropertySource
static void overrideProps(DynamicPropertyRegistry registry) {
registry.add("spring.datasource.url", mySQLContainer::getJdbcUrl);
registry.add("spring.datasource.username", mySQLContainer::getUsername);
registry.add("spring.datasource.password", mySQLContainer::getPassword);
}
@Test
@DisplayName("")
@DataSet(
value = "mock/json/admin.json",
strategy = SeedStrategy.INSERT,
cleanBefore = true,
disableConstraints = true,
cleanAfter = true,
transactional = true
)
@DisplayName("Succeded on extract / load admin")
void succeedOnExtractAndLoad() {
// GIVEN
// WHEN
List<Admin> all = adminRepository.findAll();
// THEN
assertFalse(all.isEmpty());
all.stream().map(Admin::getAdmIdx).forEach(System.out::println);
}
}
Afaik, DBRider utilizes @DBUnit , @TestExecutionListeners for Database Init / Call before test method.
I've made an assumption of
- Maybe connection is not configured to test container -> X (It was same connection)
- Maybe the version of test container matters -> X (I've tested all of the version, furthermore, there's no corelation between them if you looked at the code)
- Maybe prepared statement was not working at all for some reason -> X (I've mocked every logic of DBRider, all of them succeeded)
- Maybe invalid data format (.json) -> X ( Json was well formed, and could be able to parse it )
Here are my test codes to prove my assumptions. Be aware of singleton of test container instance.
@SpringBootTest
public class DBRiderInsertTest {
@Autowired
private AdminJpaRepository adminJpaRepository;
private final static MySQLFixture MY_SQL_FIXTURE = MySQLFixture.getInstance();
// Init db with schema
static {
JdbcDatabaseDelegate jdbcDatabaseDelegate = new JdbcDatabaseDelegate(MY_SQL_FIXTURE, "");
ScriptUtils.runInitScript(jdbcDatabaseDelegate, "mock/sql/admin.sql");
}
private final DatabaseOperation databaseOperation = DatabaseOperation.INSERT;
@Test
@DisplayName("Succeded on extract / load admin")
void succeedOnExtractAndLoad() throws SQLException, DatabaseUnitException, IOException {
// GIVEN
Connection dbConnection = DriverManager.getConnection(
MY_SQL_FIXTURE.getJdbcUrl(),
MY_SQL_FIXTURE.getUsername(),
MY_SQL_FIXTURE.getPassword()
);
ConnectionHolderImpl connectionHolder = new ConnectionHolderImpl(dbConnection);
DataSetExecutorImpl dataSetExecutor = DataSetExecutorImpl.instance(connectionHolder);
IDataSet iDataSet = dataSetExecutor.loadDataSet("mock/json/admin.json");
// WHEN
RiderDataSource riderDataSource = dataSetExecutor.getRiderDataSource();
DatabaseConnection dbUnitConnection = riderDataSource.getDBUnitConnection();
databaseOperation.execute(dbUnitConnection, iDataSet);
// THEN
try (
PreparedStatement stmt = dbConnection.prepareStatement("SELECT adm_idx FROM admin LIMIT 1");
ResultSet rs = stmt.executeQuery()
) {
boolean hasValue = rs.next();
assertTrue(hasValue);
int admIdx = rs.getInt("adm_idx");
assertTrue(admIdx > 0);
System.out.println("adm_idx = " + admIdx);
} catch (SQLException e) {
e.printStackTrace();
fail("Query failed due to SQLException: " + e.getMessage());
}
}
@Test
@DisplayName("Succeded on verification of instance connection")
void succededOnVerificationInstanceConnection() throws SQLException {
// GIVEN
// WHEN
try (Connection connection = DriverManager.getConnection(
MY_SQL_FIXTURE.getJdbcUrl(),
MY_SQL_FIXTURE.getUsername(),
MY_SQL_FIXTURE.getPassword())
) {
// THEN
assertTrue(connection.isValid(2), "Database connection is not valid");
}
}
@Test
@DisplayName("Succeded on parsing dataset of json.")
void succededOnParsingDatasetJson() throws SQLException, DataSetException, IOException {
// GIVEN
Connection dbConnection = DriverManager.getConnection(
MY_SQL_FIXTURE.getJdbcUrl(),
MY_SQL_FIXTURE.getUsername(),
MY_SQL_FIXTURE.getPassword()
);
ConnectionHolderImpl connectionHolder = new ConnectionHolderImpl(dbConnection);
DataSetExecutorImpl dataSetExecutor = DataSetExecutorImpl.instance(connectionHolder);
// WHEN
IDataSet iDataSet = dataSetExecutor.loadDataSet("mock/json/admin.json");
// THEN
ITableIterator iterator = iDataSet.iterator();
while (iterator.next()) {
ITable table = iterator.getTable();
ITableMetaData tableMetaData = table.getTableMetaData();
String tableName = tableMetaData.getTableName();
Column[] primaryKeys = tableMetaData.getPrimaryKeys();
Column[] columns = tableMetaData.getColumns();
System.out.println("tableName = " + tableName);
System.out.println("primaryKeys = " + Arrays.toString(primaryKeys));
System.out.println("columns = " + Arrays.toString(columns));
}
}
@Test
@DisplayName("Succeded on manual insertion / read by jpa.")
void succededOnManualInsertionReadByJpa() throws Exception {
// GIVEN
MySQLFixture instance = MySQLFixture.getInstance();
Connection dbConnection = DriverManager.getConnection(
instance.getJdbcUrl(),
instance.getUsername(),
instance.getPassword()
);
ConnectionHolderImpl connectionHolder = new ConnectionHolderImpl(dbConnection);
DataSetExecutorImpl dataSetExecutor = DataSetExecutorImpl.instance(connectionHolder);
IDataSet iDataSet = dataSetExecutor.loadDataSet("mock/json/admin.json");
RiderDataSource riderDataSource = dataSetExecutor.getRiderDataSource();
DatabaseConnection dbUnitConnection = riderDataSource.getDBUnitConnection();
DatabaseOperation.INSERT.execute(dbUnitConnection, iDataSet);
// WHEN
List<Admin> all = adminJpaRepository.findAll();
// THEN
assertFalse(all.isEmpty());
all.forEach(admin -> {
System.out.println("admin.getAdmIdx() : " + admin.getAdmIdx());
System.out.println("admin.getAdmId() : " + admin.getAdmId());
System.out.println("admin.getAdmPassword() : " + admin.getAdmPassword());
System.out.println("admin.getUniqueId() : " + admin.getUniqueId());
System.out.println("admin.getFullRoleName() : " + admin.getFullRoleName());
System.out.println("admin.getCreatedAt() : " + admin.getCreatedAt());
System.out.println("admin.getUpdatedAt() : " + admin.getUpdatedAt());
});
}
@Test
@DisplayName("Succeded on Spring Context's dependency over TestContainer datasource.")
void succededOnTestContainerDataSourceVerfication() throws SQLException {
// GIVEN
MySQLFixture instance = MySQLFixture.getInstance();
Connection dbConnection = DriverManager.getConnection(
instance.getJdbcUrl(),
instance.getUsername(),
instance.getPassword()
);
// WHEN
Connection connection = dataSource.getConnection();
// THEN
DatabaseMetaData metaData = connection.getMetaData();
String url = metaData.getURL();
String userName = metaData.getUserName();
DatabaseMetaData metaData1 = dbConnection.getMetaData();
String url1 = metaData1.getURL();
String userName1 = metaData1.getUserName();
assertTrue(url.contains(url1));
assertEquals(userName, userName1);
}
}
My remark on the main reason is on @DBRider annotation.
As you can see it's just a wrapper @TestExecutionListeners to run RiderRunner before the test code.
But for some reason, adding it breaks all of the assumption code above.
Is there any reason why it would not work ??

