Reputation: 198
Working code below:
//import everything
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = Test2.TestConfiguration.class)
@Transactional
public class Test2 {
@Autowired
private DataSource datasource;
@BeforeTransaction
public void createDatabase() throws SQLException {
DataSourceUtils .getConnection(datasource)
.createStatement()
.execute("CREATE TABLE USERS (id bigint, size bigint, primary key (id))");
}
@Rollback
@Test
public void test() throws SQLException {
DataSourceUtils .getConnection(datasource)
.createStatement()
.execute("INSERT INTO USERS VALUES (5, 5)");
}
@AfterTransaction
public void dropTable() throws SQLException {
ResultSet rs = DataSourceUtils .getConnection(datasource)
.createStatement()
.executeQuery("SELECT * FROM USERS");
boolean isEmpty = !rs.next();
if (isEmpty) {
System.out.println("Rollback succeeded");
} else {
System.out.println("Rollback failed");
}
rs.close();
datasource .getConnection()
.createStatement()
.execute("DROP TABLE USERS");
}
@Configuration
public static class TestConfiguration {
@Bean
public DataSource driverManagerDataSource() {
DriverManagerDataSource driverManagerDataSource = new DriverManagerDataSource();
String dbURI = "database/tests/DerbyDB/db";
String connectionString = "jdbc:derby:" + dbURI;
if (!new File(dbURI).exists()) connectionString += ";create=true";
driverManagerDataSource.setUrl(connectionString);
driverManagerDataSource.setDriverClassName("org.apache.derby.jdbc.EmbeddedDriver");
return driverManagerDataSource;
}
@Bean
public PlatformTransactionManager platformTransactionManager() {
PlatformTransactionManager ptm = new DataSourceTransactionManager(driverManagerDataSource());
return ptm;
}
}
}
Solved question: I want to rollback database state after each test using @Rollback annotation. Unfortunatelly it doesn't work.
Here is my test class:
//import everything
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = Test2.TestConfiguration.class)
@Transactional
public class Test2 {
@Autowired
private DataSource datasource;
@BeforeTransaction
public void createTable() throws SQLException {
datasource .getConnection()
.createStatement()
.execute("CREATE TABLE USERS (id bigint, size bigint, primary key (id))");
}
@Rollback
@Test
public void test() throws SQLException {
datasource .getConnection()
.createStatement()
.execute("INSERT INTO USERS VALUES (5, 5)");
}
@AfterTransaction
public void dropTable() throws SQLException {
ResultSet rs = datasource .getConnection()
.createStatement()
.executeQuery("SELECT * FROM USERS");
boolean isEmpty = !rs.next();
if (isEmpty) {
System.out.println("Rollback succeeded");
} else {
System.out.println("Rollback failed");
}
rs.close();
datasource .getConnection()
.createStatement()
.execute("DROP TABLE USERS");
}
@Configuration
public static class TestConfiguration {
@Bean
public DataSource driverManagerDataSource() {
DriverManagerDataSource driverManagerDataSource = new DriverManagerDataSource();
String dbURI = "database/tests/DerbyDB/db";
String connectionString = "jdbc:derby:" + dbURI;
if (!new File(dbURI).exists()) connectionString += ";create=true";
driverManagerDataSource.setUrl(connectionString);
driverManagerDataSource.setDriverClassName("org.apache.derby.jdbc.EmbeddedDriver");
return driverManagerDataSource;
}
@Bean
public PlatformTransactionManager platformTransactionManager() {
PlatformTransactionManager ptm = new DataSourceTransactionManager(driverManagerDataSource());
return ptm;
}
}
}
Spring claims it rolled back database, which is not true, because record remains.
How do I make it work?
gru 01, 2016 12:26:14 PM org.springframework.test.context.transaction.TransactionContext startTransaction
INFO: Began transaction (1) for test context [DefaultTestContext@457c9034 testClass = Test2, testInstance = tyvrel.tastas.persistence.Test2@345f69f3, testMethod = test@Test2, testException = [null], mergedContextConfiguration = [MergedContextConfiguration@e15b7e8 testClass = Test2, locations = '{}', classes = '{class tyvrel.tastas.persistence.Test2$TestConfiguration}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{}', contextCustomizers = set[[empty]], contextLoader = 'org.springframework.test.context.support.DelegatingSmartContextLoader', parent = [null]]]; transaction manager [org.springframework.jdbc.datasource.DataSourceTransactionManager@3bf9ce3e]; rollback [true]
gru 01, 2016 12:26:14 PM org.springframework.test.context.transaction.TransactionContext endTransaction
INFO: Rolled back transaction for test context [DefaultTestContext@457c9034 testClass = Test2, testInstance = tyvrel.tastas.persistence.Test2@345f69f3, testMethod = test@Test2, testException = [null], mergedContextConfiguration = [MergedContextConfiguration@e15b7e8 testClass = Test2, locations = '{}', classes = '{class tyvrel.tastas.persistence.Test2$TestConfiguration}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{}', contextCustomizers = set[[empty]], contextLoader = 'org.springframework.test.context.support.DelegatingSmartContextLoader', parent = [null]]].
Rollback failed
gru 01, 2016 12:26:14 PM org.springframework.context.support.GenericApplicationContext doClose
INFO: Closing org.springframework.context.support.GenericApplicationContext@ae45eb6: startup date [Thu Dec 01 12:26:12 CET 2016]; root of context hierarchy
The full log is presented below:
gru 01, 2016 12:26:12 PM org.springframework.test.context.support.DefaultTestContextBootstrapper getDefaultTestExecutionListenerClassNames
INFO: Loaded default TestExecutionListener class names from location [META-INF/spring.factories]: [org.springframework.test.context.web.ServletTestExecutionListener, org.springframework.test.context.support.DirtiesContextBeforeModesTestExecutionListener, org.springframework.test.context.support.DependencyInjectionTestExecutionListener, org.springframework.test.context.support.DirtiesContextTestExecutionListener, org.springframework.test.context.transaction.TransactionalTestExecutionListener, org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener]
gru 01, 2016 12:26:12 PM org.springframework.test.context.support.DefaultTestContextBootstrapper getTestExecutionListeners
INFO: Using TestExecutionListeners: [org.springframework.test.context.web.ServletTestExecutionListener@69d9c55, org.springframework.test.context.support.DirtiesContextBeforeModesTestExecutionListener@13a57a3b, org.springframework.test.context.support.DependencyInjectionTestExecutionListener@7ca48474, org.springframework.test.context.support.DirtiesContextTestExecutionListener@337d0578, org.springframework.test.context.transaction.TransactionalTestExecutionListener@59e84876, org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener@61a485d2]
gru 01, 2016 12:26:12 PM org.springframework.context.support.GenericApplicationContext prepareRefresh
INFO: Refreshing org.springframework.context.support.GenericApplicationContext@ae45eb6: startup date [Thu Dec 01 12:26:12 CET 2016]; root of context hierarchy
gru 01, 2016 12:26:13 PM org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor <init>
INFO: JSR-330 'javax.inject.Inject' annotation found and supported for autowiring
gru 01, 2016 12:26:13 PM org.springframework.jdbc.datasource.DriverManagerDataSource setDriverClassName
INFO: Loaded JDBC driver: org.apache.derby.jdbc.EmbeddedDriver
gru 01, 2016 12:26:14 PM org.springframework.test.context.transaction.TransactionContext startTransaction
INFO: Began transaction (1) for test context [DefaultTestContext@457c9034 testClass = Test2, testInstance = tyvrel.tastas.persistence.Test2@345f69f3, testMethod = test@Test2, testException = [null], mergedContextConfiguration = [MergedContextConfiguration@e15b7e8 testClass = Test2, locations = '{}', classes = '{class tyvrel.tastas.persistence.Test2$TestConfiguration}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{}', contextCustomizers = set[[empty]], contextLoader = 'org.springframework.test.context.support.DelegatingSmartContextLoader', parent = [null]]]; transaction manager [org.springframework.jdbc.datasource.DataSourceTransactionManager@3bf9ce3e]; rollback [true]
gru 01, 2016 12:26:14 PM org.springframework.test.context.transaction.TransactionContext endTransaction
INFO: Rolled back transaction for test context [DefaultTestContext@457c9034 testClass = Test2, testInstance = tyvrel.tastas.persistence.Test2@345f69f3, testMethod = test@Test2, testException = [null], mergedContextConfiguration = [MergedContextConfiguration@e15b7e8 testClass = Test2, locations = '{}', classes = '{class tyvrel.tastas.persistence.Test2$TestConfiguration}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{}', contextCustomizers = set[[empty]], contextLoader = 'org.springframework.test.context.support.DelegatingSmartContextLoader', parent = [null]]].
Rollback failed
gru 01, 2016 12:26:14 PM org.springframework.context.support.GenericApplicationContext doClose
INFO: Closing org.springframework.context.support.GenericApplicationContext@ae45eb6: startup date [Thu Dec 01 12:26:12 CET 2016]; root of context hierarchy
Upvotes: 2
Views: 3709
Reputation: 420
I think this line con.close();
in printTableName()
method caused the issuse.
The transaction is committed when closing the connection.
It is better use entitymanager or spring data jpa repository to handle the transaction.
Upvotes: 0
Reputation: 12450
From what I understand, you're creating a new, independent Spring context manually in your test method, which during its initialization creates the table.
Since that context uses its own transaction manager and data source, it won't be affected by the @Rollback
annotation - that one is processed in context of the (implicit) spring context defined for the whole test class.
Also note that in some DBs, you cannot rollback CREATE
commands (not sure about Derby though).
Update
Another issue is that you're not actually using the transaction manager when you get the connection through datasource.getConnection()
.
From DataSourceTransactionManager
documentation:
Application code is required to retrieve the JDBC Connection via
DataSourceUtils.getConnection(DataSource)
instead of a standard Java EE-styleDataSource.getConnection()
call. Spring classes such asJdbcTemplate
use this strategy implicitly.
Upvotes: 2