我有一些代码(生产中):
这引起了LazyInitializationException
。
虽然我知道如何解决这个问题,但我希望能够对此进行测试。但是,我无法弄清楚如何在测试的正确部分重新创建异常。
我必须用一些测试数据来填充数据库,因此我的测试用@Transactional
注释。如果不这样做会导致设置失败......你猜对了...... LazyInitializationException
。
这是我目前的测试:
@Transactional
public class UpdateCachedMarketPricingActionTest extends AbstractIntegrationTest {
@Autowired
private UpdateCachedMarketPricingAction action;
@Autowired
private PopulateMarketCachesTask populateMarketCachesTask;
@Test @SneakyThrows
public void updatesCachedValues()
{
// Populate the cache from a different thread, as this is how it happens in real life
Thread updater = new Thread(new Runnable() {
@Override
public void run() {
populateMarketCachesTask.populateCaches();
}
});
updater.start();
updater.join();
updateMessage = {...} //ommitted
action.processInstrumentUpdate(updateMessage);
}
所以,我在一个单独的线程中启动我的缓存,试图让它超出当前的@Transaction
范围。此外,我还在缓存引用中调用entityManager.detatch(entity)
,以确保缓存中存在的实体无法加载其集合。
然而,测试通过......没有抛出任何异常。
我如何强制让一个实体进入一个状态,当我下次尝试迭代它的集合时,它会抛出LazyInitializationException
?
答案 0 :(得分:0)
您需要确保每个操作的事务都是相互独立的。使用@Tranactional
注释测试方法或测试类会使当前测试事务处于打开状态,然后在执行整个测试后将其回滚。
因此,一种选择是执行以下操作:
@Autowired
private PlatformTransactionManager transactionManager;
@Test
public void example() {
new TransactionTemplate(transactionManager).execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus status) {
// add your code here...
}
});
}
您可以在自己的回调中调用第一个操作,然后在另一个回调中调用第二个操作。然后,当您在回调之后访问Hibernate或JPA实体时,实体将不再附加到当前工作单元(例如,Hibernate Session
)。因此,在该点访问延迟集合或字段将导致LazyInitializationException
。
此致
萨姆
P.S。请注意,此技术自然会将更改提交到您的数据库。因此,如果您需要清理修改后的状态,请考虑使用@AfterTransaction
方法手动执行此操作。