Akka Jaworek
Akka Jaworek

Reputation: 2120

testing HQL query on hbm2dll with Junit

How can I test HQL query with JUnit tests?

I have mapped Entity Class:

@Entity
@Table(name = "DOE")
public DomainObjectEntity {
    //some attributes
}

which represents domain objects:

public class DomainObject {
     //some attributes
}

I also have repository interface for my domain objects:

 public interface DomainObjectRepository {

     /**
     * Gets entity by some attribute
     * 
     */
     DomainObject getDomainObjectByObjectId(String objectId);
}

this interface is implemented in

 @Repository
 public class DomainObjectRepositoryImpl implements DomainObjectRepository {

     @Inject
     private DomainObjectEntityJPARepository entityRepository;

    @Override
     public DomainObjectgetDomainObjectById(String parcelId) {
        //this converts my entity to domain object
        return entityRepository.findByDomainObjectId(DomainObjectId.getStr()).getDomainObject(); 
    }

}

my JPA Entity repository looks like this:

public interface DomainObjectEntityJPARepository extends  JpaRepository<DomainObjectEntity, String> {
    /**
     * get DomainObject with requested id
     * 
     * @param objectId - objects id
     * @return DomainObject
     */
    @Query("some query to be tested")
    DomainObjectEntity findByDomainObjectId(@Param("objectId") String objectId);
}

and finally i want to write a simple JUnit test to check if query to findByDomainObjectId returns the correct object. I think my test should look like this:

  1. create test object to put into DB
  2. retrieve object from DB
  3. compare objects

i have setted up a hbm2dll with import.sql to create and populate my DB but how can i access it from Junit test by calling method findByDomainObjectId?

Upvotes: 2

Views: 1622

Answers (2)

Akka Jaworek
Akka Jaworek

Reputation: 2120

Since I wanted to test only query, proper solution was to @autowire JPArepository and then in setup, populate it with data, this way tests were bound only with DB structure and not the data inside

 public class EntityObjectJPARepositoryTest {

     @Autowired
     DomainObjectEntityJPARepository domainObjectRepo;

     DomainObjectEntity entity;

     @Before
     public void Setup(){
           entity = new DomainObjectEntity ()
           //setup entity
           domainObjectRepo.save(entity);
      }

      @Test
      public void testfindByDomainObjectId(){
           DomainObjectEntity res = domainObjectRepo.findByDomainObjectId(objectid);
           Assert.assertEquals(entity.getId(), res.getId());
      }
     //everything else
 }

Upvotes: 0

mmalmeida
mmalmeida

Reputation: 1057

Unit vs integration

First of all there is one thing you need to ask:

  1. Do you want an Unit test or an Integration test

An unit test is fast (ie, milliseconds) to run and is, well, unitary - meaning it doesn't touch the database.

An integration test is heavier and, in case of a database test, will touch the db.

While it is usually preferable to create unit tests, in your case it seems you want an integration test - you actually want to test the call to the database and check if the query does what you think it does.

When to load data

I would suggest that in your integration test you don't preload data with import.sql (or at least think very carefully if this is what you want). The reason for this is that, as your test suite grows, you'll need the database in one state for test A, another state for test B, and so on, and you'll quickly end up in a situation where you'll have incompatible states.

You'll also end up with slower tests if you load too much data via SQL.

My advise would be: try to create/manipulate the data in your test.

How to test

How to test it depends on how you load your hibernate in production. Judging by the code you've shown, I believe you might be using a Dependency injection mechanism to start up hibernate's EntityManager (or SessionFactory), like Spring.

If this is the case, you can use spring to configure you integration test. The main suggestions here would be:

  1. Use rollback so that data is not stored between tests (guarantees test independence)
  2. As your test suite grows, create an abstract class that holds the configuration and, e.g, exposes the EntityManager/sessionFactory. All your integration tests just need to extend this class, have the repository injected (in your example, inject DomainObjectRepositoryImpl into the test) and run the method you need to test.

Below is a very simple abstract test I have (in my case I'm using a SessionFactory):

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.AbstractTransactionalJUnit4SpringContextTests;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.transaction.TransactionConfiguration;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={
        "/spring-SF-tests.xml",
        "/spring-transaction.xml"
})
@TransactionConfiguration(transactionManager="txManager", defaultRollback=true)
public abstract class HibernateAbstractTest extends AbstractTransactionalJUnit4SpringContextTests {
@Autowired
protected SessionFactory sessionFactory;

public void setSessionFactory(SessionFactory sessionFactory){
    this.sessionFactory = sessionFactory;
}

public Session getSession(){
    return sessionFactory.getCurrentSession();
}

public void save(Object object){
    getSession().save(object);
}

public void update(Object object){
    getSession().update(object);
}
}

Upvotes: 1

Related Questions