Как вы тестируете Spring @Transactional, не обращаясь к кэшу 1-го уровня гибернации или не делая ручную очистку сессии?

Использование Spring + Hibernate и транзакционных аннотаций.

Я пытаюсь проверить следующее:

вызовите метод, который изменяет объект пользователя, затем вызывает@Transactional метод обслуживания, чтобы сохранить егопрочитайте объект обратно из БД и убедитесь, что его значения верны после метода

Первая проблема, с которой я столкнулся при чтении объекта User на шаге 2, просто вернула объект в кэш-памяти уровня 1 Hibernate и фактически не читала из базы данных.

Поэтому я вручную извлек объект из кэша, используя Session для принудительного чтения из базы данных. Однако, когда я делаю это, значения объекта никогда не сохраняются в модульном тесте (я знаю, что он откатывается после завершения теста из-за настроек, которые я указал).

Я попытался вручную сбросить сессию после вызова@Transactional метод обслуживания, и что DID фиксирует изменения. Однако я не ожидал этого. Я думал, что@Transactional Сервисный метод обеспечит фиксацию транзакции и сброс сеанса до его возврата. Я знаю, что в общем Spring решит, когда делать это управление, но я думал, что «единица работы» в@Transactional метод был этот метод.

В любом случае, сейчас я пытаюсь выяснить, как я буду тестировать@Transactional метод в целом.

Вот метод испытания junit, который терпит неудачу:

@RunWith(SpringJUnit4ClassRunner.class)
@Transactional
@TransactionConfiguration(transactionManager = "userTransactionManager", defaultRollback = true)
@WebAppConfiguration()
@ContextConfiguration(locations = { "classpath:test-applicationContext.xml",
        "classpath:test-spring-servlet.xml",
        "classpath:test-applicationContext-security.xml" })
public class HibernateTest {

    @Autowired
    @Qualifier("userSessionFactory")
    private SessionFactory sessionFactory;

    @Autowired
    private UserService userService;

    @Autowired
    private PaymentService paymentService;

    @Autowired
    private QueryService queryService;

    @Autowired
    private NodeService nodeService;

    @Autowired
    private UserUtils userUtils;

    @Autowired
    private UserContext userContext;

  @Test
    public void testTransactions() {
        // read the user
        User user1 = userService.readUser(new Long(77));
        // change the display name
        user1.setDisplayName("somethingNew");
        // update the user using service method that is marked @Transactional
        userService.updateUserSamePassword(user1);
        // when I manually flush the session everything works, suggesting the
        // @Transactional has not flushed it at the end of the method marked
        // @Transactional, which implies it is leaving the transaction open?
        // session.flush();
        // evict the user from hibernate level 1 cache to insure we are reading
        // raw from the database on next read
        sessionFactory.getCurrentSession().evict(user1);
        // try to read the user again
        User user2 = userService.readUser(new Long(77));
        System.out.println("user1 displayName is " + user1.getDisplayName());
        System.out.println("user2 displayName is " + user2.getDisplayName());
        assertEquals(user1.getDisplayName(), user2.getDisplayName());
    }
}

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

Сервисный метод для updateUserSamePassword находится здесь:

@Transactional("userTransactionManager")
@Override
public void updateUserSamePassword(User user) {
    userDAO.updateUser(user);
}

Метод DAO здесь:

@Override
public void updateUser(User user) {
    Session session = sessionFactory.getCurrentSession();
    session.update(user);
}

SesssionFactory имеет автоматическую связь:

@Autowired
@Qualifier("userSessionFactory")
private SessionFactory sessionFactory;

Я использую конфигурацию контекста приложения XML. Я имею:

<context:annotation-config />
<tx:annotation-driven transaction-manager="userTransactionManager" />

А также

<bean id="userDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close"> 
    <property name="driverClass" value="${user.jdbc.driverClass}"/>
    <property name="jdbcUrl" value="${user.jdbc.jdbcUrl}" />
    <property name="user" value="${user.jdbc.user}" />
    <property name="password" value="${user.jdbc.password}" />
    <property name="initialPoolSize" value="3" />
    <property name="minPoolSize" value="1" />
    <property name="maxPoolSize" value="17" />
</bean>

<bean id="userSessionFactory"
    class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
    <property name="dataSource" ref="userDataSource" />
    <property name="configLocation" value="classpath:user.hibernate.cfg.xml" />
</bean>

<bean id="userTransactionManager"
    class="org.springframework.orm.hibernate4.HibernateTransactionManager">
    <property name="dataSource" ref="userDataSource" />
    <property name="sessionFactory" ref="userSessionFactory" />
</bean>

Также есть проверка компонентов на сервисах и классах дао. Как я уже сказал, это работает в производстве.

Я думал, что если у меня есть помеченный метод@Transactional что к концу этого метода (например, метод обновления здесь) Spring заставит Session зафиксировать и очистить.

Я вижу только несколько вариантов:

Я что-то неправильно настроил, хотя это работает для меня в целом (только не модульные тесты). Есть догадки? Есть идеи, как это проверить?

Что-то в самих настройках модульного теста ведет себя не так, как приложение.

Транзакции и сессии не работают так. Мой единственный вывод заключается в том, что Spring оставляет транзакцию и / или сессию открытой после вызова этого метода обновления. Поэтому, когда я вручную выселяю пользователя из объекта Session, эти изменения еще не зафиксированы.

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

То есть, как мне переписать свой юнит-тест здесь?

Есть еще идеи?

Ответы на вопрос(2)

Ваш ответ на вопрос