2016-11-29 2 views
1

Рабочий код ниже:Spring-тест в не откатить ничего

//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; 
     } 
    } 
} 

решаемый вопрос: Я хочу, чтобы откатить состояние базы данных после каждого теста с использованием @Rollback аннотацию. К сожалению, это не сработает.

Вот мой тестовый класс:

//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 утверждает, что откат базы данных, которая не является правдой, потому что запись остается.
Как заставить его работать?

gru 01, 2016 12:26:14 PM org.springframework.test.context.transaction.TransactionContext startTransaction 
INFO: Began transaction (1) for test context [[email protected] testClass = Test2, testInstance = [email protected]5f69f3, testMethod = [email protected], testException = [null], mergedContextConfiguration = [[email protected] 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 [o[email protected]3bf9ce3e]; rollback [true] 
gru 01, 2016 12:26:14 PM org.springframework.test.context.transaction.TransactionContext endTransaction 
INFO: Rolled back transaction for test context [[email protected] testClass = Test2, testInstance = [email protected], testMethod = [email protected], testException = [null], mergedContextConfiguration = [[email protected] 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 [email protected]45eb6: startup date [Thu Dec 01 12:26:12 CET 2016]; root of context hierarchy 

Полный журнал представлен ниже:

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: [or[email protected]69d9c55, org.springframework.test[email protected]13a57a3b, org.springframewor[email protected]7ca48474, org.springfra[email protected]337d0578, org.springframew[email protected]59e84876, org.sp[email protected]61a485d2] 
gru 01, 2016 12:26:12 PM org.springframework.context.support.GenericApplicationContext prepareRefresh 
INFO: Refreshing [email protected]45eb6: 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 [[email protected] testClass = Test2, testInstance = [email protected], testMethod = [email protected], testException = [null], mergedContextConfiguration = [[email protected] 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 [o[email protected]3bf9ce3e]; rollback [true] 
gru 01, 2016 12:26:14 PM org.springframework.test.context.transaction.TransactionContext endTransaction 
INFO: Rolled back transaction for test context [[email protected] testClass = Test2, testInstance = [email protected], testMethod = [email protected], testException = [null], mergedContextConfiguration = [[email protected] 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 [email protected]45eb6: startup date [Thu Dec 01 12:26:12 CET 2016]; root of context hierarchy 

ответ

2

Из того, что я понимаю, вы создаете новый независимый контекст Spring вручную в методе тестирования, который во время инициализации создает таблицу.

Поскольку в этом контексте используется собственный диспетчер транзакций и источник данных, на него не влияет аннотация - @Rollback - тот обрабатывается в контексте (неявного) весеннего контекста, определенного для всего тестового класса.


Также обратите внимание, что в некоторых БД, вы не можете откатить CREATE команды (не уверен, Дерби, хотя).


Update

Другая проблема заключается в том, что вы на самом деле не с помощью менеджера транзакций, когда вы получаете соединение через datasource.getConnection().

Из DataSourceTransactionManager документации:

Код приложения требуется, чтобы получить соединение JDBC через DataSourceUtils.getConnection(DataSource) вместо стандартного Java EE стиле DataSource.getConnection() вызова. Классы Spring, такие как JdbcTemplate, используют эту стратегию неявно.

+0

Вы имеете в виду, что аннотирование тестового класса с помощью '@ContextConfiguration (classes = TestDerbyDatabaseInitializer.TestConfiguration.class)' и удаление контекста implict сделает аннотацию '@ Rollback'? – Tyvrel

+1

1) Вам нужно использовать контекст Spring, созданный аннотацией '@ ContextConfiguration' (т. Е. Делать то, что вы написали); не создавайте каких-либо других контекстов, чтобы избежать путаницы, 2) не создавайте никаких программных связей с базой данных ('DriverManager.getConnection()'), чтобы избежать случайного использования неконтролируемого подключения, 3) проверить его на то, что вы знаете можно отбросить назад (т.е.'INSERT', а не' CREATE TABLE') - создайте базу данных в методе '@ BeforeTransaction'. –

+0

Спасибо, этот ответ заставил меня больше узнать о тестировании Spring. Также я обновил код в соответствии с вашим комментарием, но я все еще не могу заставить его работать. – Tyvrel

0

Я думаю, что эта линия con.close(); в printTableName() метод вызван.

Сделка совершается при закрытии соединения.

Лучше использовать entitymanager или spring data jpa repository для обработки транзакции.

+0

К сожалению, удаление 'con.close();' не решает проблему. – Tyvrel

+0

@Tyvrel Вы пытались явно откат? 'con.rollback();' – Bryan

+0

Конечно. Это тоже не работает. И не хватает смысла - мне нужно научиться тому, как работает «@ Rollback», и я не мог понять, что делать проще, чем выполнять простой скрипт sql. – Tyvrel

Смежные вопросы