Turbut Alin Turbut Alin - 5 months ago 20
Java Question

Hibernate's PreUpdateEventListener not being called in unit tests

I am trying to test my PreUpdateEventListener flow, but I cannot seem to make it work in the JUnit tests. I am not getting any error, but the code is not called.

My PreUpdateEventListener:

@Component
public class CandidateListener implements PreUpdateEventListener {

@Autowired
EntityManagerFactory entityManagerFactory;

@PostConstruct
private void init() {
HibernateEntityManagerFactory hibernateEntityManagerFactory = (HibernateEntityManagerFactory) this.entityManagerFactory;
SessionFactoryImpl sessionFactoryImpl = (SessionFactoryImpl) hibernateEntityManagerFactory.getSessionFactory();
EventListenerRegistry registry = sessionFactoryImpl.getServiceRegistry().getService(EventListenerRegistry.class);
registry.appendListeners(EventType.POST_LOAD, this);
registry.appendListeners(EventType.PRE_UPDATE, this);
}

@Override
public boolean onPreUpdate(PreUpdateEvent event) {
final Object entity = event.getEntity();
if (entity == null) return false;

// code here not being called in unit tests, but works fine on server

return false;
}

}


The test:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = Application.class)
@WebAppConfiguration
@IntegrationTest
@Transactional
public class CandidateListenerTest {

@Autowired
CandidateRepository candidateRepository;

@Autowired
EntityAuditEventRepository entityAuditEventRepository;

@Autowired
SessionFactory sessionFactory;

@Test
public void testHistoryLogging() {
Candidate cand = new Candidate();
cand.setEmail("123@gmail.com");
cand.setFirstName("12");
cand.setLastName("3");

cand = candidateRepository.save(cand);

cand.setLastName("34");
candidateRepository.save(cand);

assertEquals(entityAuditEventRepository.findAll().size(), 1);
}

}


I have tried injecting the SessionFactory into the test and calling SessionFactory#flush method, but that throws
No CurrentContextSession
error, which I cannot seem to fix.

Answer

Finally managed to fix this.

What I have kept trying to do was to inject the EntityManager and call flush from there, but there would have been no change in the actual output (the code was still not being called).

The solution for me was inspired from here making my final test look like this:

@Test
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void testHistoryLogging() {
    Candidate cand = new Candidate();
    cand.setEmail("123@gmail.com");
    cand.setFirstName("12");
    cand.setLastName("3");

    cand = candidateRepository.save(cand);

    cand.setLastName("34");
    candidateRepository.save(cand);

    assertEquals(entityAuditEventRepository.findAll().size(), 1);

}

Basically every call is executed non-transactionally, which saves the candidate into the database after the save method from the repository is called.

Comments