使用 Spring + Hibernate 和事务注释。
我正在尝试测试以下内容:
- 调用一个改变用户对象的方法,然后调用一个
@Transactional
服务方法来持久化它 - 从数据库中读回对象并确保在方法之后它的值是正确的
我遇到的第一个问题是在第 2 步中读取 User 对象只是返回了 Hibernate 1 级缓存中的那个,并且实际上并没有从数据库中读取。
因此,我使用 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);
}
SessionFactory 是自动装配的:
@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>
还对服务和 dao 类进行了组件扫描。正如我所说,这是在生产中工作的。
我认为如果我在该方法@Transactional
结束时有一个方法标记为该方法(例如这里的更新方法),Spring 会强制 Session 提交和刷新。
我只能看到几个选项:
我错误地配置了一些东西,即使这对我来说一般都有效(只是不是单元测试)。有什么猜测吗?关于如何测试这个的任何想法?
关于单元测试配置本身的某些事情与应用程序的行为方式不同。
事务和会话不是那样工作的。我唯一的推断是 Spring 在调用该更新方法后使事务和/或会话保持打开状态。因此,当我在 Session 对象上手动驱逐用户时,这些更改尚未提交。
谁能确认这是否是预期的行为?不应该@Transaction
在会话中强制提交和刷新?如果不是,那么如何测试标记的方法@Transactional
并且这些方法实际上与事务一起使用?
即,我应该如何在这里重写我的单元测试?
还有其他想法吗?