Транзакція відкоту після @Test


85

Перш за все, я знайшов багато тем на StackOverflow про це, але жоден з них мені дійсно не допоміг, так що шкода задати, можливо, повторюване запитання.

Я запускаю тести 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


Що ви маєте на увазі під відкатом? Очищення бази даних?
Gaurav,

5
встановивши його в точно такий же стан, як і після виконанняinitTest
Ян Ворчак

Відповіді:


127

Просто додайте @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або на рівні класу, або методу для своїх тестів .


2
ну, я спробував це раніше, і це все ще не працює, можливо ... може проблема полягає в тому, що я не визначив PlatformTransactionManager, як я можу це зробити?
Ян Ворчак,

@javo: як ви модифікуєте базу даних? Якщо ви використовуєте Jpa / Hibernate / JdbcTemplate / ... їх повинно бути PlatformTransactionManager. Інакше як Spring дізнається про ваші транзакції та базу даних?
Томаш Нуркевич,

1
Посилання у цій відповіді більше не є правильним; див . відповідь користувача2418306 нижче для правильного посилання та додаткового контексту з документації Spring.
DaveyDaveDave

1
Я не працюю, кожен метод вимагає окремої транзакції, не можу це зробити для цілого класу
Каміль Неканович

Я тестую вкладиш у таблицю. З @Transactional команда вставки навіть не видається проти бази даних (я бачу це, оскільки консоль має сплячий режим show-sql true). У багатьох випадках чудово працює. Але один із моїх тестів перевіряє, що база даних видає DataAccessException через обмеження бази даних. У цьому випадку тест не вдається, оскільки відкат відбувається "в пам'яті", і база даних ніколи не викликається. Рішення: використовувати @Transactionalна рівні @Testметоду, а не на рівні класу.
Паулу Мерсон,

17

Крім: спроба внести зміни у відповідь Томаша Нуркевича була відхилена:

Ця редакція не робить публікацію навіть трохи легшою для читання, легшою для пошуку, точнішою чи доступнішою. Зміни або зовсім зайві, або активно шкодять читабельності.


Правильне та постійне посилання на відповідний розділ документації про інтеграційне тестування.

Щоб увімкнути підтримку транзакцій, потрібно налаштувати PlatformTransactionManagerкомпонент, ApplicationContextщо завантажується за допомогою @ContextConfigurationсемантики.

@ Конфігурація
@PropertySource ("application.properties")
громадський клас Наполегливість {
    @Autowired
    Навколишнє середовище;

    @ Бін
    DataSource dataSource () {
        повернути новий DriverManagerDataSource (
                env.getProperty ("datasource.url"),
                env.getProperty ("datasource.user"),
                env.getProperty ("datasource.password")
        );
    }

    @ Бін
    PlatformTransactionManager transactionManager () {
        повернути новий DataSourceTransactionManager (dataSource ());
    }
}

Крім того, ви повинні оголосити @Transactionalанотацію Spring або на рівні класу, або методу для ваших тестів.

@RunWith (SpringJUnit4ClassRunner.class)
@ContextConfiguration (класи = {Persistence.class, SomeRepository.class})
@Transactional
публічний клас SomeRepositoryTest {...}

Анотація методу тестування @Transactionalпризводить до того, що тест запускається в межах транзакції, яка за замовчуванням автоматично відкочується назад після завершення тесту. Якщо до тестового класу додано примітки @Transactional, кожен тестовий метод у цій ієрархії класів буде запущений в рамках транзакції.


12

Відповіді, в яких згадується додавання, @Transactionalє правильними, але для простоти ви можете просто пройти свій тестовий клас extends AbstractTransactionalJUnit4SpringContextTests.


1
додавання анотації '@Transactional' на рівні класу не працює, додавання анотації '@Transactional' окремо для кожної функції працює, і розширення AbstractTransactionalJUnit4SpringContextTests теж працює
Каміль Неканович

5

Я знаю, я занадто запізнився з публікацією відповіді, але сподіваюся, що це може комусь допомогти. Крім того, я щойно вирішив цю проблему своїми тестами. Це те, що я мав у своєму тесті:

Мій тестовий клас

@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" />

Сподіваюся, це допоможе.


Ну, отже, ви вручаєте свої твердження вручну? Ви впевнені, що ваші дані навіть були записані у вашу базу даних?
franta kocourek

Для тих, хто бореться з розумінням весняних транзакцій, переконайтеся, що для джерела даних НЕ встановлено автоматичне фіксацію, або ви зведете себе з розуму, намагаючись з’ясувати, чому @Transactional, здається, нічого не робить.
Джо Ернст,

2

Вам потрібно запустити тест із контекстом Spring та менеджером транзакцій, наприклад,

@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
     }
}

Докладнішу інформацію див. У розділі 3.5.8. Transaction Management«Довідковий джерело».



-4

Ви можете відключити відкат:

@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();
    }
}

6
Це якраз навпаки, про що вимагає ОП
Адам Міхалік

Це повинен був бути коментар до прийнятої відповіді.
DerMike 13.03.18
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.