Using Spring + Hibernate and transactional annotations.
I am trying to verify the following:
- calling a method that modifies the user object, then calling the
@Transactional service method to save it - read the object back from the database and make sure that the values ββare correct after the method
The first problem I encountered was reading the User object in step 2, which had just returned Hibernate 1 in the cache and had not actually read from the database.
Therefore, I manually deleted the object from the cache using a session to force it to read from the database. However, when I do this, the values ββof the object are never stored in the unit test (I know that it returns after the test is completed due to the settings I specified).
I tried to manually clear the session after calling the @Transactional service @Transactional , and the DID committed the changes. However, I did not expect this. I thought the @Transactional service method @Transactional provide the transaction and be @Transactional before it was returned. I know that in general, Spring will decide when to do this management, but I thought the "unit of work" in the @Transactional method is a method.
Anyway, now I'm trying to figure out how I would test the @Transactional method as a whole.
There is no junit validation method here:
@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() {
If I manually cleared the session, the test will succeed. However, I expected the @Transactional method @Transactional take care of committing and clearing the session.
The service method for updateUserSamePassword is here:
@Transactional("userTransactionManager") @Override public void updateUserSamePassword(User user) { userDAO.updateUser(user); }
The DAO method is here:
@Override public void updateUser(User user) { Session session = sessionFactory.getCurrentSession(); session.update(user); }
SesssionFactory auto-increments:
@Autowired @Qualifier("userSessionFactory") private SessionFactory sessionFactory;
I am using the context configuration of an XML application. I have:
<context:annotation-config /> <tx:annotation-driven transaction-manager="userTransactionManager" />
and
<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>
There is also a check on the components of services and dao classes. As I said, this works in production.
I thought that if I have a method marked with @Transactional that by the end of this method (like the update method here), Spring would force Session to commit and reset.
I see only a few options:
I have configured something incorrectly, although this works for me in general (just not unit tests). Any guesses? Any ideas on how to check this?
Something in the unit test configuration is not behaving as the application should have been.
Transactions and sessions do not work. My only conclusion is that Spring leaves the transaction and / or session open after calling this update method. Therefore, when I manually preempt a user in a Session object, these changes have not yet been committed.
Can anyone confirm that this is the expected behavior? Shouldn't @Transaction force and hide a session? If not, how can I test a method labeled @Transactional and that the methods really work with transactions?
Ie, how do I rewrite unit test here?
Any other ideas?