Spring3 / Hibernate3 / TestNG:一些测试给出了LazyInitializationException,有些则没有

前言:我在unit testing中遇到了LazyInitializationException,我很难理解它,你可以从我的问题中看到Spring , TestNG和Spring 3中的 数据库会话以及unit testingHibernate时的LazyInitializationException使用TestNG在Spring中使用的实体类

为了能够清楚地提出我的问题,我在GitHub上做了一个示例项目: http : //github.com/niklassaers/Sample-Spring3-App/在这个示例项目中,我重现了我面临的问题在我的Spring3 / Hibernate3 / TestNG项目中。

问题:我有两个unit testing,它们非常相似,使用相同的服务测试相同类的相同类。 一个运行,一个运行失败。 为什么失败的失败? (或者,为什么跑步者不会以同样的方式失败?)

这是失败的测试:

@Test(timeOut=1000) public void Roles() { User mockUser = userService.read(1); Assert.assertNotNull(mockUser); Assert.assertTrue(mockUser.isValid()); Set roles = mockUser.getRoles(); int size = roles.size(); // This line gives a LazyInitializationException Assert.assertTrue(size > 0); } 

完整代码( http://github.com/niklassaers/Sample-Spring3-App/blob/master/src/tld/mydomain/sample/entities/test/FailingUserUnitTest.java )

这是运行测试:

 @Test public void Roles() { for(int i = 1; i <= 4; i++) { User user = userService.read(i); Assert.assertNotNull(user); Assert.assertTrue(user.isValid()); Set roles = user.getRoles(); Assert.assertTrue(roles.size() > 0); // This line does not give a LazyInitializationException for(Role r : roles) { Assert.assertNotNull(r.getName()); for(User someUser : r.getUsers()) Assert.assertNotNull(someUser.getName()); } } } 

完整代码( http://github.com/niklassaers/Sample-Spring3-App/blob/master/src/tld/mydomain/sample/entities/test/UserUnitTest.java )

下面是运行我的测试的控制台输出。 我知道我有一个包装在TransactionProxyFactoryBean中的服务(参见http://github.com/niklassaers/Sample-Spring3-App/blob/master/WebRoot/WEB-INF/App-Model.xml ),这使得它们运行在一个事务中,unit testing没有被包装,使得测试就像一个视图。 我用OpenSessionInViewInterceptor“修复”的视图。 但是我已经知道在从AbstractTransactionTestNGSpringContextTests扩展的类中使用@Test注释的每个unit testing也应该包装在它自己的事务中,事实上我已经注释了两个类以在每个测试完成后回滚事务。 这就是为什么我对为什么一个测试失败而一个没有失败感到困惑。 任何线索或解决方案?

您可以根据需要随意修改GitHub上的示例项目,所有代码都应该在那里,但为了简单起见,我省略了jar文件。 这是承诺的完整输出:

 [Parser] Running: /Users/niklas/Documents/Eclipse/SampleProject/testng.xml 2009-10-15 10:16:16,066 [TestNGInvoker-Roles()] ERROR org.hibernate.LazyInitializationException - failed to lazily initialize a collection of role: tld.mydomain.sample.entities.User.roles, no session or session was closed org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: tld.mydomain.sample.entities.User.roles, no session or session was closed at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:380) at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationExceptionIfNotConnected(AbstractPersistentCollection.java:372) at org.hibernate.collection.AbstractPersistentCollection.readSize(AbstractPersistentCollection.java:119) at org.hibernate.collection.PersistentSet.size(PersistentSet.java:162) at tld.mydomain.sample.entities.test.FailingUserUnitTest.Roles(FailingUserUnitTest.java:33) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at org.testng.internal.MethodHelper.invokeMethod(MethodHelper.java:607) at org.testng.internal.InvokeMethodRunnable.runOne(InvokeMethodRunnable.java:49) at org.testng.internal.InvokeMethodRunnable.run(InvokeMethodRunnable.java:40) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:441) at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303) at java.util.concurrent.FutureTask.run(FutureTask.java:138) at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908) at java.lang.Thread.run(Thread.java:637) =============================================== SampleAppSuite Total tests run: 3, Failures: 1, Skips: 0 =============================================== 

干杯

从@Test注释中删除timeOut = 1000。 看起来这导致测试在一个单独的线程中运行(很明显,堆栈跟踪会从ThreadPool中抛出exception)。 事务和SessionFactory绑定到主线程,而不是测试运行程序的线程,这导致此exception。

我已经运行了您的示例代码并且已经让测试工作了。 将来,如果您将Maven2 pom.xml与您的依赖项一起包含在内,那么对于那些尝试编译代码的人来说,实际上这样做会更容易。