Dear Sirs,
The preface: I'm struggeling with LazyInitializationException in my Unit Tests, and I have a really hard time getting my head around it, as you can see from my questions Database Sessions in Spring, TestNG and Spring 3 and LazyInitializationException while unit-testing Hibernate entity classes for use in Spring, using TestNG
In order to be able to ask my question clearly, I've made a sample project on GitHub: http://github.com/niklassaers/Sample-Spring3-App/ In this sample project, I reproduce the problems I'm facing in my Spring3/Hibernate3/TestNG projects.
The question: I have two unit tests, they are quite alike, test the same class for the same collection of items using the same service. One runs, one fails. Why does the failing one fail? (or, why doesn't the running one fail in the same way?)
Here is the failing test:
@Test(timeOut=1000)
public void Roles() {
User mockUser = userService.read(1);
Assert.assertNotNull(mockUser);
Assert.assertTrue(mockUser.isValid());
Set<Role> roles = mockUser.getRoles();
int size = roles.size(); // This line gives a LazyInitializationException
Assert.assertTrue(size > 0);
}
full code at ( http://github.com/niklassaers/Sample-Spring3-App/blob/master/src/tld/mydomain/sample/entities/test/FailingUserUnitTest.java )
and here is the running test:
@Test
public void Roles() {
for(int i = 1; i <= 4; i++) {
User user = userService.read(i);
Assert.assertNotNull(user);
Assert.assertTrue(user.isValid());
Set<Role> 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());
}
}
}
full code at ( http://github.com/niklassaers/Sample-Spring3-App/blob/master/src/tld/mydomain/sample/entities/test/UserUnitTest.java )
Below follows the console output from running my tests. I understand that I have the services wrapped in a TransactionProxyFactoryBean (see http://github.com/niklassaers/Sample-Spring3-App/blob/master/WebRoot/WEB-INF/App-Model.xml), that makes them run in a transaction, and the unit tests are not wrapped, making the test like a view. The views I've "fixed" with OpenSessionInViewInterceptor. But I have learned that each unit test annotated with @Test in a class that extends from AbstractTransactionalTestNGSpringContextTests should also be wrapped in its own transaction, and indeed I've annotated both classes to rollback the transaction after each test is finished. That's why I'm doubly puzzled as to why one test fails and one does not. Any clues or solutions?
Feel free to modify the sample project at GitHub as you see fit, all the code should be there, but I've left out the jar-files for simplicity's sake. Here's the full output as promised:
[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
===============================================
Cheers
Nik