Question

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

Was it helpful?

Solution

Remove the timeOut=1000 from the @Test annotation. It appears that this is causing the test to be run in a separate thread (as is evident by the stacktrace, where the exception is thrown from a ThreadPool). Transactions and the SessionFactory are bound to the main thread, not to the test runner's thread, which is causing this exception.

I have run your example code and have gotten the test to work. In the future, it would be handy if you included a Maven2 pom.xml with your dependencies so that it is easier for those trying to compile your code to actually do so.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top