Unable to get results with EntityManager when using junit

I got following query which gives zero results in unit test when using EntityManager implementation listDailyExpenses(). However if I use the listDailyExpensesNonEm() implantation within test, I get correct result count. Why does it behave differently?

Hibernate query which generate for both methods are identical.

And this issue only occur during unit test, through the web application both methods produce same results.

SampleTest.java

@SpringBootTest(classes = TestAppContext.class)
@Sql({ "/test-data.sql" })
public class SampleTest {

    @Autowired
    DailyExpensesDao dailyExpensesDao;
    // **** this test fail
    @Test
    void testListExpenses() {
        List<DailyExpense> list = dailyExpensesDao.listDailyExpenses();
        assertEquals(5, list.size());

    }  
}

DailyExpensesDaoImpl.java - Implementation of two methods

@Repository
@Transactional
public class DailyExpensesDaoImpl extends AbstractHibernateDao<DailyExpense> implements DailyExpensesDao {
    private static final Logger logger = LogManager.getLogger(DailyExpensesDaoImpl.class);

    public DailyExpensesDaoImpl() {
        super();
        setClazz(DailyExpense.class);
    }

    @Override
    public List<DailyExpense> listDailyExpenses() {
        
        EntityManager entityManager = getCurrentSession().getEntityManagerFactory().createEntityManager();

        CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
        CriteriaQuery<DailyExpense> criteriaQuery = criteriaBuilder.createQuery(DailyExpense.class);
        Root<DailyExpense> root = criteriaQuery.from(DailyExpense.class);
        criteriaQuery.select(root);
        TypedQuery<DailyExpense> typedQuery = entityManager.createQuery(criteriaQuery);
        List<DailyExpense> list = typedQuery.getResultList();
        return list;
    }
    
    @Override
    public List<DailyExpense> listDailyExpensesNonEm() {        
        List<DailyExpense> list = getCurrentSession().createQuery("from DailyExpense").list();
        logger.debug("listPersons size of items " + list.size());
        return list;
    }

TestAppContext.java - Test Configuration class

@Configuration
@PropertySource("classpath:test-database.properties")
@EnableTransactionManagement
@ComponentScan(basePackages = {
        "org.d.money.dao", "org.d.money.service", "org.d.money.model"
})
public class TestAppContext {
    
    private static final Logger logger = LogManager.getLogger(TestAppContext.class);
    
    
    @Autowired
    private Environment environment;    
    
    @Bean
    public LocalSessionFactoryBean sessionFactory() {
        logger.debug("getting session fac");
        LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
        sessionFactory.setDataSource(dataSource());
        sessionFactory.setPackagesToScan(new String[] {
            "org.decserv.money.model"
        });
        sessionFactory.setHibernateProperties(hibernateProperties());
        return sessionFactory;
    }

    @Bean
    public DataSource dataSource() {
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName(environment.getRequiredProperty("jdbc.driverClassName"));
        dataSource.setUrl(environment.getRequiredProperty("jdbc.url"));
        dataSource.setUsername(environment.getRequiredProperty("jdbc.username"));
        dataSource.setPassword(environment.getRequiredProperty("jdbc.password"));
        return dataSource;
    }

    private Properties hibernateProperties() {
        Properties properties = new Properties();
        properties.put("hibernate.dialect", environment.getRequiredProperty("hibernate.dialect"));
        properties.put("hibernate.show_sql", environment.getRequiredProperty("hibernate.show_sql"));
        properties.put("hibernate.format_sql", environment.getRequiredProperty("hibernate.format_sql"));
        properties.put("hibernate.hbm2ddl.auto", environment.getRequiredProperty("hibernate.hbm2ddl.auto"));
        //https://stackoverflow.com/questions/21574236/how-to-fix-org-hibernate-lazyinitializationexception-could-not-initialize-prox
        properties.put("hibernate.enable_lazy_load_no_trans", environment.getRequiredProperty("hibernate.enable_lazy_load_no_trans"));
        return properties;
    }

    @Bean
    public HibernateTransactionManager getTransactionManager() {
        HibernateTransactionManager transactionManager = new HibernateTransactionManager();
        transactionManager.setSessionFactory(sessionFactory().getObject());
        return transactionManager;
    }

Here is my hibernate properties

    private Properties hibernateProperties() {
        Properties properties = new Properties();
        properties.put("hibernate.dialect", environment.getRequiredProperty("hibernate.dialect"));
        properties.put("hibernate.show_sql", environment.getRequiredProperty("hibernate.show_sql"));
        properties.put("hibernate.format_sql", environment.getRequiredProperty("hibernate.format_sql"));
        properties.put("hibernate.hbm2ddl.auto", environment.getRequiredProperty("hibernate.hbm2ddl.auto"));
        properties.put("hibernate.enable_lazy_load_no_trans", true);
        return properties;
    }

Using
hibernate 5.6.8.Final
org.springframework.boot 2.7.4

Hey @boomramada, thanks for reaching out. This question seems to be not really related to Hibernate Search, but more to the ORM. I’ll move it under that category.

As for the reason why you see a different behaviour - from what it seems - you are using Spring which runs tests in transactions, so that would mean that when you call

you are within the same transaction and the same underlying entity manager in which you’ve created the test data.

But when you do

you would get a new entity manager that is not aware what you’ve done. But when you run the app and not the tests your data would already be persisted and available in the db when you start the transaction to query it - so it doesn’t make a difference which of the approaches you take.

The ORM folks might give you a better explanation :smiley:

The post by @mbekhta perfectly explains what is happening and I couldn’t have explained it better.

Thanks @mbekhta and well explained the behaviour, now what would be the best approach on unit test this method (one with entity manager) with H2? I got number of methods which use CriteriaBuilder, I’m try to test them without mocking the entity manger.

Simply don’t use this:

EntityManager entityManager = getCurrentSession().getEntityManagerFactory().createEntityManager();

but this instead:

EntityManager entityManager = getCurrentSession();

Thanks guys for putting me in correct path, I found a issue here as well, it should be getCurrentSesssion() .createQuery(criteriaQuery); not entityManager.createQuery(criteriaQuery);