2

My unit tests are seeing org.hibernate.LazyInitializationException: could not initialize proxy [org.openapitools.entity.MenuItem#5] - no Session. I'm not sure why they expect a session in a unit test. I'm trying to write to an in-memory h2 database for the unit tests of my Controller classes that implement the RESTful APIs. I'm not using any mock objects for the test, because I want to test the actual database transactions. This worked fine when I was using Spring-Boot version 1.x, but broke when I moved to version 2. (I'm not sure if that's what caused the tests to break, since I made lots of other changes. My point is that my code has passed these tests already.)

My Repositories extend JPARepository, so I'm using a standard Hibernate interface.

There are many answers to this question on StackOverflow, but very few describe a solution that I could use with Spring-Data.

Addendum: Here's a look at the unit test:

@Test
public void testDeleteOption() throws ResponseException {
  MenuItemDto menuItemDto = createPizzaMenuItem();
  ResponseEntity<CreatedResponse> responseEntity 
      = adminApiController.addMenuItem(menuItemDto);
  final CreatedResponse body = responseEntity.getBody();
  assertNotNull(body);

  Integer id = body.getId();
  MenuItem item = menuItemApiController.getMenuItemTestOnly(id);
  // Hibernate.initialize(item); // attempted fix blows up
  List<String> nameList = new LinkedList<>();
  for (MenuItemOption option : item.getAllowedOptions()) { // blows up here
    nameList.add(option.getName());
  }
  assertThat(nameList, hasItems("pepperoni", "olives", "onions"));
  // ... (more code)
}

My test application.properties has these settings

spring.datasource.url=jdbc:h2:mem:pizzaChallenge;DB_CLOSE_ON_EXIT=FALSE
spring.datasource.username=pizza
spring.datasource.password=pizza
spring.jpa.show-sql=true
1
  • 2
    Could you post some code? Commented Jan 19, 2021 at 13:46

2 Answers 2

4

I found a way around this. I'm not sure if this is the best approach, so if anyone has any better ideas, I'd appreciate hearing from them.

Here's what I did. First of all, before reading a value from the lazy-loaded entity, I call Hibernate.initialize(item);

This throws the same exception. But now I can add a property to the test version of application.properties that says

spring.jpa.properties.hibernate.enable_lazy_load_no_trans=true

Now the initialize method will work.

P.S. I haven't been able to find a good reference for Spring properties like this one. If anyone knows where I can see the available properties, I'd love to hear about it. The folks at Spring don't do a very good job of documenting these properties. Even when they mention a specific property, they don't provide a link that might explain it more thoroughly.

Sign up to request clarification or add additional context in comments.

1 Comment

You ARE the reference. This solved my problem, thank you!!!
2

This is not standard Hibernate, but spring data. You have to understand that Hibernate uses lazy loading to avoid loading the whole object graph from the database. If you close the session or connection to the database e.g. by ending a transaction, Hibernate can't lazy load anymore and apparently, your code tries to access state that needs lazy loading.

You can use @EntityGraph on your repository to specify that an association should be fetched or you avoid accessing the state that isn't initialized outside of a transaction. Maybe you just need to enlarge the transaction scope by putting @Transactional on the method that calls the repository and accesses the state, so that lazy loading works.

3 Comments

I should add that it works fine in production. I just need to fix the unit test. So I hesitate to change the production code to fix this.
Also, there's no session.
Maybe in production the entity MenuItem#5 is put into the first level cache through other means which does not happen in your test, but I wouldn't rely on this.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.