Issue
Please give me tips to get my failing JUnit test to pass in my Spring Boot app.
I have a Service that needs to delete rows from tables A and B (from a H2 database) in a transactional manner such that: if A is modified and then an exception occurs before B is modified, then neither A nor B are modified. However, even after
- Adding
@Transactional
to the PUBLICService::deleteRows
method, and - Adding
@EnableTransactionManagement
to the@Configuration
class that produces theJdbcTemplate
that all repositories use, and - Confirming that spring-tx is on the classpath
the transaction still doesn't rollback.
Here's the failing JUnit testcase
// Service.java
@Transactional
public void deleteRows() {
aRepository.deleteRow(123);
bRepository.deleteRow(123);
}
// ServiceTest.java
@Test
void test() {
// first ensure that an exception is thrown when bRepository.deleteRow() is called
// FYI deleteRow() calls jdbcTemplate.update()
doThrow(RuntimeException.class)
.when(mockJdbcTemplate)
.update(any(), eq(123));
BRepository mockBRepository = new BRepository(mockJdbcTemplate);
Service service = new Service(realARepository, mockBRepository);
assertTableHasRows(1, "TABLE_A"); // before calling the service, TABLE_A has 1 row
assertThrows(RuntimeException.class, service::deleteRows);
assertTableHasRows(1, "TABLE_A"); // TABLE_A should still have 1 row when an exception occurs during the tx
}
Solution
In the end the problem was solved by NOT using mocking to trigger an exception. Instead, we set up the database schema so that normal operation of service::deleteRows would trigger an exception.
Answered By - user2042190
Answer Checked By - Gilberto Lyons (JavaFixing Admin)