Hibernate Unit tests - Reset schema - java

I'm testing the CRUD operations of my DAOs in JUnit tests.
When i execute the single test, Hibernate always resets the schema and populates the DB in a known state. But when i execute multiple tests in a row, Hibernate resets the schema once, and then the data is accumulated during the execution of the tests.
This is an unexpected behavior, so I'd like to add in the #Before method of the tests a function that explicitly resets the schema to avoid the pesistence of side data created by previous tests during the execution chain.
Any tips?
Thanks

First of all, what you're doing is not unit testing, it's integration testiong.
Tips:
Use transactions and roll the back.
Consider using DBUnit (not sure how helpful it would be in your case).
Here's some relevant code from org.springframework.orm.hibernate3.LocalSessionFactoryBean.
...
Connection con = session.connection();
Dialect dialect = Dialect.getDialect(getConfiguration().getProperties());
String[] sql = getConfiguration().generateSchemaCreationScript(dialect);
executeSchemaScript(con, sql);

You could begin a transaction before and rollback the transaction each #Test method, something like this:
public class HibernateIntegrationTest {
protected static SessionFactory factory;
protected Session session;
#BeforeClass
public static void createSessionFactory() {
AnnotationConfiguration config = new AnnotationConfiguration();
// ...
config.configure();
factory = config.buildSessionFactory();
}
#AfterClass
public static void closeSessionFactory() {
if (factory != null) {
factory.close();
}
}
#Before
public void beginTransaction() {
session = factory.getCurrentSession();
session.beginTransaction();
}
#After
public void rollbackTransaction() {
if (session.getTransaction().isActive()) {
session.getTransaction().rollback();
}
if (session.isOpen()) {
session.close();
}
}
}
And extend this class in your tests classes.
public class DemoTest extends HibernateIntegrationTest {
#Test
public void createMyEntity() {
MyEntity e = new MyEntity();
//...
session.save(e);
assertNotNull(e.getId());
}
}
Note that this is not the cleanest way to do this, the code above is more for demonstration purposes.

Related

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.
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.

org.hibernate.StaleStateException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1

I am writing unit test case using JUnit in STS.The classes are
TestConfiguration.java
#Configuration
#ComponentScan("com.kgfsl.collections.core")
public class TestConfiguration {
#Bean
#Inject
public org.hibernate.SessionFactory sessionFactory(DataSource dataSource) {
LocalSessionFactoryBuilder sessionBuilder = new
LocalSessionFactoryBuilder(dataSource);
sessionBuilder.scanPackages("com.kgfsl.collections.core.models");
sessionBuilder.addProperties(getHibernateProperties());
return sessionBuilder.buildSessionFactory();
}
private static Properties getHibernateProperties() {
final org.hibernate.cfg.Configuration configuration = new
org.hibernate.cfg.Configuration();
configuration.setProperty(HBM2DDL_AUTO, "create");
configuration.setProperty(DIALECT, "org.hibernate.dialect.MySQL5Dialect");
// Test Default settings
configuration.setProperty(CURRENT_SESSION_CONTEXT_CLASS, "thread");
configuration.setProperty(USE_GET_GENERATED_KEYS, "true");
configuration.setProperty(USE_REFLECTION_OPTIMIZER, "true");
configuration.setProperty(ORDER_UPDATES, "true");
configuration.setProperty(ORDER_INSERTS, "true");
configuration.setProperty(USE_NEW_ID_GENERATOR_MAPPINGS, "true");
return configuration.getProperties();
}
}
BaseRepositoryTest.java
#RunWith (SpringJUnit4ClassRunner. class)
#ContextConfiguration(classes = {UserManagementTestConfiguration.class})
public abstract class BaseRepositoryTest extends
AbstractJUnit4SpringContextTests {
#Inject
SessionFactory sessionFactory;
private Transaction transaction;
public Session getSession() {
Session session;
try {
session = sessionFactory.getCurrentSession();
} catch (SessionException se) {
session = sessionFactory.openSession();
}
return session;
}
#Before
public void setUp() throws Exception {
transaction = getSession().beginTransaction();
}
#After
public void tearDown() throws Exception {
if (transaction != null) {
transaction.rollback();
}
getSession().close();
}
#Before
public void baseSetUp() {
MockitoAnnotations.initMocks(this);
}
}
UserRoleDaoTest.java
public class UserRoleDaoTest extends BaseRepositoryTest
{
#Autowired
private UserRoleDao userroleDao;
#Test
public void shouldCreateRole()
{
UserRole userRole=new UserRoleBuilder().userroleBuilder(10,"Md Aslam",
"N","1").build();
UserRole userroleCreated=userroleDao.persist(userRole);
UserRole userroleGet = userroleDao.findById(userroleCreated.getRoleId());
Assert.assertThat(userroleGet.getRoleName(), Is.is("Md Aslam"));
Assert.assertThat(userroleGet.getRoleId(), Is.is(10));
UserRole userroleCreate=userroleDao.persist(userRole);
Assert.assertNotNull(userRole.getRoleId());
}
#Test
public void shouldGetRoleById()
{
UserRole userRole=new UserRoleBuilder().userroleBuilder(10,"Md Aslam",
"N","1").build();
UserRole userroleCreated=userroleDao.persist(userRole);
UserRole userroleGet = userroleDao.findById(userroleCreated.getRoleId());
assertNotNull(userroleGet);
Assert.assertThat(userroleGet.getRoleId(), Is.is(10));
}
#Test
public void shouldUpdateAccount()
{
UserRole userRole=new UserRoleBuilder().userroleBuilder(10,"aslam",
"N","1").build();
UserRole userroleCreated=userroleDao.persist(userRole);
UserRole userroleGet = userroleDao.findById(userroleCreated.getRoleId());
Assert.assertEquals(userRole.getRoleId(), userroleGet.getRoleId());
UserRole userRoleForUpdate=new
UserRoleBuilder().userroleBuilder(userroleCreated.getRoleId(),"Md Aslam",
"Y","1").build();
userroleDao.update(userRoleForUpdate);
}
#Test
public void shouldGetRoleByName()
{
UserRole userRole=new UserRoleBuilder().userroleBuilder(10,"aslam",
"N","1").build();
UserRole userroleCreated=userroleDao.persist(userRole);
UserRole userrolegetbyname=userroleDao.findByRoleName(userRole.getRoleName());
assertNotNull(userrolegetbyname);
}
}
When I run this class, it shows error like
shouldGetRoleByName:org.hibernate.StaleStateException: Batch update returned
unexpected row count from Update [0]; actual row count: 0; expected: 1
The actual method for shouldGetRoleByName is that
public UserRole findByRoleName(String roleName) {
UserRole userPermission = (UserRole)
criteria().setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY)
.add(eq("roleName", roleName.trim().toLowerCase())).uniqueResult();
return userPermission;
}
All methods in the test case are passed except shouldGetRoleByName () this method.And
I tried in many ways but I can't get a solution for it, if anybody knows the solution for it please help me.
It seems Hibernate is keeping all changes in memory and executing a flush (send the changes to database) only when a query is triggered in the "shouldGetRoleByName" method.
At this time the update called in the "shouldUpdateAccount" is sent to the database and it fails (affects zero records).
Try to invoke "flush" at the end of the "shouldUpdateAccount" method and check if the error moves to there. If so, you can investigate your code to better understand its behaviour. Note that all entities modifications performed in a session are sent to the database only at specific times (ex: when you commit a transacion or when you execute a query).
100% working solution!!!! just write save instead of saveOrUpdate in your hibernate query... because due to previous logs your class is generating some other id which was previously stored in ur table ,so hibernate tries to update with same id and it finds no row with that id so it gives staleStateException.

JPA EntityManager blocks after #Transactional method

I have a Spring-JUnit test with a setup method that uses JPA Entities to setup test data. Within the test itself, legacy code uses JDBC-Templates to query the inserted test data. When the legacy code issues a query, the call to jdbcTemplate.query(...) hangs.
My Unit Test looks like this:
#TransactionConfiguration(defaultRollback = false)
#ContextConfiguration(locations = { "/testContext.xml" })
#Transactional
public class MyTest {
#PersistenceContext(unitName = "someUnit")
private EntityManager entityManager;
#Test
public void test() {
// here some legacy Code is called that uses JDBC Templates to query
// the inserted test data. The legacy code hangs upon jdbcTemplate.query(...)
}
#Before
public void before() {
this.entityManager.persist(new Entity1(...));
this.entityManager.persist(new Entity2(...));
}
}
My question is: Why doesn't the enitymanager commit upon exiting the before() method? Or does it commit and immediately start a new transaction, that still references the stored entity? I also tried to do without the junit annotation #Before annotation and manually call the before() method. But this gives the same result.
Any advice is highly appreciated.
Test class
#ContextConfiguration(locations = { "/testContext.xml" })
#TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = false)
#RunWith(SpringJUnit4ClassRunner.class)
#Transactional
public class MyTest extends AbstractTransactionalJUnit4SpringContextTests{
#PersistenceContext(unitName = "someUnit")
private EntityManager entityManager;
#Autowired
private BeforeService beforeService;
#Test
public void test() {
beforeService.before();
// here some legacy Code is called that uses JDBC Templates to query
// the inserted test data. The legacy code hangs upon jdbcTemplate.query(...)
}
}
Before Service
public class BeforeService {
private EntityManager entityManager;
#PersistenceContext
public void setEntityManager(final EntityManager entityManager) {
this.entityManager = entityManager;
}
#Transactional(propagation=Propagation.REQUIRES_NEW)
public void before() {
entityManager.persist(new Entity1(...));
entityManager.persist(new Entity2(...));
}
}
I hope I've given you all the answers about your question.

org.hibernate.LazyInitializationException: could not initialize proxy -no Session

I am getting this bug when I run a test case(Junit) for spring application.
I searched for this problem and I got the information that whenever a lazy initialization occurs and my application tries to get second level data while session is closed(object become detached) then this error occurs, we can't make initialization as EAGER as its performance issue.
My testing class contains :
#RunWith(SpringJUnit4ClassRunner.class)
public class MyTestClass extends AbstractControllerTest {
#Rule
public TestName testMethodName = new TestName();
#Before
public void setUp() throws Exception
{
super.setUp();
}
#After
public void tearDown() throws Exception
{
super.tearDown();
}
#Test
public void myTestMethod ()
{
assertTrue("Response Validating",validate(baseEntity,perform()));
}
}
Is there a way that can I put method assertTrue("Response Validating",validate(baseEntity,perform())); in a transaction can bind with current session or with new session so that my detached object become persistent object and then My application can get second level data also. I searched for this problem and I found a solution on link : http://www.jroller.com/RickHigh/entry/hibernate_spring_simulating_an_opensessioninviewfilter
but this link does not fulfil my requirement as it requires target object on which transaction is to be created.
#Test
#Transactional
public void myTestMethod ()
{
assertTrue("Response Validating",validate(baseEntity,perform()));
}
Annotate myTestMethod with #Transactional (assuming you're using annotation-based configuration).
I got the solution for this problem. I was implementing OpenSessionInViewFilter in my testing code to overcome this problem but was doing silly mistake.
Please take a look on following code :
#Autowired
BeanFactory bf;
#Before
public void setUp() throws Exception
{
sessionFactory = (SessionFactory) bf.getBean("sessionFactory");
Session session = SessionFactoryUtils.getSession(sessionFactory, true);
session.setFlushMode(FlushMode.NEVER);
TransactionSynchronizationManager.bindResource(sessionFactory, new SessionHolder(session));
}
#After
public void tearDown() throws Exception
{
super.tearDown();
SessionHolder sessionHolder = (SessionHolder) TransactionSynchronizationManager.unbindResource(sessionFactory);
Session session = sessionHolder.getSession();
SessionFactoryUtils.closeSession(session);
}
Earlier I was not using
session.setFlushMode(FlushMode.NEVER) this was the mistake.
BTW thanks

How to close resources shared between junits?

I have many junit 4 test classes with many tests.
Many of these tests need a DataSource to access a database.
To speed up tests, I would like to share a single DataSource for all test classes.
That would avoid connection cost.
So I have put the DataSource in a static variable.
But I have not found a way to close it!
With #Rule + TestWatcher, we can execute code before and after a single test...
With #ClassRule + TestWatcher, we can execute code before and after a single test class...
But how to execute code after the execution of all executed test classes ?
The test suite doesn't seems appropriate, because I am executing either all, one, or any subset of the junits tests.
Any idea?
You can use ClassRule
public static class GlobalDataSource extends ExternalResource
private int count = 0;
private DataSource dataSource;
private GlobalDataSource() {};
public static final GlobalDataSource INSTANCE = new GlobalDataSource();
public DataSource get() {
if (dataSource == null) {
throw new IllegalStateException();
}
return dataSource;
}
#Override
protected void before() throws Throwable {
if (count++ == 0) {
dataSource = createDataSource();
}
}
#Override
protected void after() {
if (--count == 0) {
try {
destroyDataSource(dataSource);
} finally {
dataSource = null;
}
}
};
};
In your tests:
#RunWith(JUnit4.class)
public class FooTest {
#ClassRule public static GlobalDataSource source = GlobalDataSource.INSTANCE;
#Test
public void readDataSource() {
...
}
}
Then create a suite:
#RunWith(Suite.class)
#SuiteClasses(FooTest.class, BarTest.class ...)
public class AllTests {
#ClassRule public static GlobalDataSource source = GlobalDataSource.INSTANCE;
}
Be aware that global state in tests can be just as problematic as global state in code. A failure in one test could lead other tests to fail.
Installing JVM shutdown hook does not appear too ugly in that case.
Far more reliable than a finalize() method called only if the object is garbage collected.
Not called if process interrupted, but in that case there nothing can be done anyway. So I did not find major drawbacks.
Thanks.

Categories

Resources