Откат транзакции после @Test

Во-первых, я обнаружил множество тем в Stackru по этому поводу, но ни одна из них мне не помогла, так что извините, возможно, задаю двойной вопрос.

Я запускаю тесты JUnit с использованием spring-test, мой код выглядит так

@RunWith(SpringJUnit4ClassRunner.class)  
@ContextConfiguration(locations = {})
public class StudentSystemTest {

    @Autowired
    private StudentSystem studentSystem;

    @Before
    public void initTest() {
    // set up the database, create basic structure for testing
    }

    @Test
    public void test1() {
    }    
    ...  
}

Моя проблема в том, что я хочу, чтобы мои тесты НЕ влияли на другие тесты. Поэтому я хотел бы создать что-то вроде отката для каждого теста. Я много искал для этого, но пока ничего не нашел. Я использую Hibernate и MySql для этого

8 ответов

Решение

Просто добавь @Transactional аннотация поверх вашего теста:

@RunWith(SpringJUnit4ClassRunner.class)  
@ContextConfiguration(locations = {"testContext.xml"})
@Transactional
public class StudentSystemTest {

По умолчанию Spring запускает новую транзакцию вокруг вашего метода тестирования и @Before / @After обратные вызовы, откат в конце. Он работает по умолчанию, достаточно иметь некоторый менеджер транзакций в контексте.

С: 10.3.5.4 Управление транзакциями (жирный рудник):

В платформе TestContext транзакции управляются TransactionalTestExecutionListener. Обратите внимание, что TransactionalTestExecutionListener настроен по умолчанию, даже если вы явно не объявляете @TestExecutionListeners на вашем тестовом классе. Однако, чтобы включить поддержку транзакций, вы должны предоставить PlatformTransactionManager бин в контексте приложения, загруженного @ContextConfiguration семантика. Кроме того, вы должны объявить @Transactional либо на уровне класса или метода для ваших тестов.

В сторону : попытка изменить ответ Томаша Нуркевича была отклонена:

Это изменение не делает сообщение даже немного легче для чтения, легче найти, более точным или более доступным. Изменения либо полностью излишни, либо активно вредят читабельности.


Правильная и постоянная ссылка на соответствующий раздел документации об интеграционном тестировании.

Чтобы включить поддержку транзакций, вы должны настроить PlatformTransactionManager боб в ApplicationContext загружается через @ContextConfiguration семантика.

@Configuration
@PropertySource ("application.properties")
народный класс
    @Autowired
    Окружающая среда;

    @Bean
    DataSource dataSource() {
        вернуть новый DriverManagerDataSource(
                env.getProperty("datasource.url"),
                env.getProperty("datasource.user"),
                env.getProperty("datasource.password"));
    }

    @Bean
    PlatformTransactionManager TransactionsManager() {
        вернуть новый DataSourceTransactionManager(dataSource());
    }
}

Кроме того, вы должны объявить Spring @Transactional аннотации на уровне класса или метода для ваших тестов.

@RunWith (SpringJUnit4ClassRunner.class)
@ContextConfiguration (classes = {Persistence.class, SomeRepository.class})
@Transactional
открытый класс SomeRepositoryTest { ... }

Аннотирование метода испытаний с @Transactional вызывает выполнение теста в транзакции, которая по умолчанию автоматически откатывается после завершения теста. Если тестовый класс помечен @Transactionalкаждый тестовый метод в этой иерархии классов будет выполняться внутри транзакции.

Ответы с упоминанием добавления @Transactional правильно, но для простоты вы могли бы просто иметь свой тестовый класс extends AbstractTransactionalJUnit4SpringContextTests,

Помимо добавления @Transactional на @Test метод, вам также необходимо добавить @Rollback(false)

Я знаю, я слишком поздно, чтобы опубликовать ответ, но надеюсь, что это может кому-то помочь. Плюс, я только что решил эту проблему с моими тестами. Вот что у меня было в моем тесте:

Мой тестовый класс

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "path-to-context" })
@Transactional
public class MyIntegrationTest 

Контекст xml

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
   <property name="driverClassName" value="${jdbc.driverClassName}" />
   <property name="url" value="${jdbc.url}" />
   <property name="username" value="${jdbc.username}" />
   <property name="password" value="${jdbc.password}" />
</bean>

У меня все еще была проблема, что база данных не очищалась автоматически.

Проблема была решена, когда я добавил следующее свойство в BasicDataSource

<property name="defaultAutoCommit" value="false" />

Надеюсь, поможет.

Вам нужно запустить свой тест с контекстом спринта и менеджером транзакций, например,

@RunWith(SpringJUnit4ClassRunner.class)  
@ContextConfiguration(locations = {"/your-applicationContext.xml"})
@TransactionConfiguration(transactionManager="txMgr")
public class StudentSystemTest {

     @Test
     public void testTransactionalService() {
         // test transactional service
     }

     @Test
     @Transactional
     public void testNonTransactionalService() {
         // test non-transactional service
     }
}

См главу 10. Testing весны ссылки для получения дополнительной информации.

Как было сказано выше в ответе, получившем наибольшее количество лайков, по сути, вам нужно всего лишь 2 вещи ниже, чтобы откат транзакции происходил в тестовых случаях:

  • добавьте @Transactional в тестовый класс
  • добавьте @Rollback в тестовый пример

Если это по-прежнему не работает, дважды проверьте, использует ли ваша система несколько источников данных. Если да, вам также необходимо указать ожидаемый источник данных для транзакции в зависимости от того, к какой БД будет подключаться ваш SQL.

Пример кода:

      @SpringBootTest(classes = Sample.class)
@Transactional(transactionManager = "txManagerXX") // specify txManager here if your system uses multiple sources
public class SampleTest {

    @Test
    @Rollback
    public void test_case_1(){
        ...
    }

}

Вы можете отключить откат:

@TransactionConfiguration(defaultRollback = false)

Пример:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = Application.class)
@Transactional
@TransactionConfiguration(defaultRollback = false)
public class Test {
    @PersistenceContext
    private EntityManager em;

    @org.junit.Test
    public void menge() {
        PersistentObject object = new PersistentObject();
        em.persist(object);
        em.flush();
    }
}
Другие вопросы по тегам