Spring Hibernate Repository Testing with jUnit

11,694

Your tests do not automatically reset the persisted data. There are a couple of alternatives for solving or working around that:

1. Add the @Transactional annotation to the tests.

Transactional tests are run in a transaction that gets rolled back after the test finishes, clearing any state persisted by the test. However, adding @Transactional might hide some errors. See this article about it.

2. Create an @After method that cleans any persisted changes

This might be cumbersome to maintain since you need to keep track of everything that the tests persist. One slightly more complicated but maintainable way to do this is to dump the DB before running the tests and then restore it from that dump after every test.

3. Implement the tests in a way that they don't break even if the DB already contains something.

Example:

@Test
public void testEntityGetsPersisted() {
    int countBefore = getCurrentCountOfEntities();
    persistNewEntity();
    int countAfter = getCurrentCountOfEntities();
    assertTrue(countAfter == countBefore + 1);
}
Share:
11,694
Amit
Author by

Amit

Updated on June 04, 2022

Comments

  • Amit
    Amit almost 2 years

    First of all I am a newcomer for Spring + Hibernate development. Followed lots of tutorials books and I have created a sample application mainly on Spring, Hibernate based on the standards, I have started writing some test cases for Repository (DAO) methods ie find, findAll, save, delete.

    Its really crazy when i execute the test class not all of the test cases execute properly for ex. particularly find & findAll methods. But when run them individually they pass perfectly.

    Entity

    @Entity
    @Table(name = "client_master")
    public class ClientMaster {
    
    private Long id;
    private Long version;
    private Date dateCreated;
    private Date lastUpdated;
    private String clientName;
    
    private List<ProjectMaster> projectMaster;
    
    @Id
    @GeneratedValue
    public Long getId() {
        return id;
    }
    
    public void setId(Long id) {
        this.id = id;
    }
    
    @Version
    @Column(name = "version")
    public Long getVersion() {
        return version;
    }
    
    public void setVersion(Long version) {
        this.version = version;
    }
    
    @Column(name = "client_name", nullable= false,unique= true)
    public String getClientName() {
        return clientName;
    }
    
    public void setClientName(String clientName) {
        this.clientName = clientName;
    }
    
    @OneToMany(targetEntity = ProjectMaster.class, mappedBy = "lientMaster", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    public List<ProjectMaster> getProjectMaster() {
        return projectMaster;
    }
    
    public void setProjectMaster(List<ProjectMaster> ProjectMaster) {
        this.projectMaster = projectMaster;
    }
    
    @Column(name = "date_created" , nullable= false)
    @Temporal(TemporalType.TIMESTAMP)
    public Date getDateCreated() {
        return dateCreated;
    }
    
    public void setDateCreated(Date dateCreated) {
        this.dateCreated = dateCreated;
    }
    
    @Column(name = "last_updated")
    @Temporal(TemporalType.TIMESTAMP)
    public Date getLastUpdated() {
        return lastUpdated;
    }
    
    public void setLastUpdated(Date lastUpdated) {
        this.lastUpdated = lastUpdated;
    }
    
    }  
    

    Repository

    import java.util.List;
    import javax.persistence.EntityNotFoundException;
    import org.hibernate.Query;
    
    @Repository("clientMasterRepo")
    @Transactional
    public class ClientMasterRepoHibernate implements ClientMasterRepository {
    
    @Autowired
    private SessionFactory sessionFactory;
    
    @Override
    public ClientMaster find(Long id) {     
        // Based on the Hibernate currentsession get the ClientMaster Object based on Id        
        ClientMaster clientMaster = (ClientMaster) sessionFactory.getCurrentSession().get(ClientMaster.class, id);              
        return clientMaster;
    }
    
    @Override
    public List<ClientMaster> findAll() {
        // Get all the ClientMaster records.
        Query query = sessionFactory.getCurrentSession().createQuery("FROM ClientMaster");
        List<ClientMaster> clientMasterList = query.list();
        return clientMasterList;
    
    }
    
    @Override
    public ClientMaster save(ClientMaster clientMaster) {
        // Insert or Update the ClientMaster object
        sessionFactory.getCurrentSession().saveOrUpdate(clientMaster);
        return CclientMaster;       
    }
    
    @Override
    public void delete(ClientMaster clientMaster) {
        // Delete the ClientMaster object
        sessionFactory.getCurrentSession().delete(clientMaster);
    }
    
    }
    

    JUnit Tests

    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(locations={"file:src/main/resources/META-INF/spring/spring-master.xml"})  
    public class ClientMasterRepositoryTests {
    
    @Autowired
    private ClientMasterRepository clientMasterRepository;
    
    private List<ClientMaster> ClientMasterList;
    
    @Before
    public void setup(){
        // Initialize ClientMaster mock objects for testing     
        ClientMasterList = new ArrayList<ClientMaster>();
    
        ClientMaster client1 = new ClientMaster();
        client1.setClientName("Client1");
        client1.setDateCreated(new Date());
        client1.setLastUpdated(new Date());
    
        ClientMaster client2 = new ClientMaster();
        client2.setClientName("Client2");
        client2.setDateCreated(new Date());
        client2.setLastUpdated(new Date());
    
        ClientMaster client3 = new ClientMaster();
        client3.setClientName("Client3");
        client3.setDateCreated(new Date());
        client3.setLastUpdated(new Date());
    
        ClientMaster client4 = new ClientMaster();
        client4.setClientName("Client4");
        client4.setDateCreated(new Date());
        client4.setLastUpdated(new Date());
    
        ClientMasterList.add(client1);
        ClientMasterList.add(client2);
        ClientMasterList.add(client3);
        ClientMasterList.add(client4);      
    }
    
    @Test
    public void testSave(){     
        for (Iterator iterator = ClientMasterList.iterator(); iterator.hasNext();) {
            ClientMaster ClientMaster = (ClientMaster) iterator.next(); 
    
            // insert the ClientMaster object 
            clientMasterRepository.save(ClientMaster);
    
            assertTrue(ClientMaster.getClientName()+" is saved - Id "+ClientMaster.getId(),ClientMaster.getId() > 0);
        }       
    }
    
    @Test
    public void testUpdate(){
        // get a ClientMaster object from the repository
        ClientMaster clientMasterObj = clientMasterRepository.find(1L);
    
        // assert if its not null
        assertTrue(!clientMasterObj.getClientName().isEmpty());
    
        // change the client name 
        clientMasterObj.setClientName("Client1-Changed");
    
        // update the ClientMaster object
        clientMasterRepository.save(clientMasterObj);
    
        // assert the value changed id true
        assertEquals("Client1-Changed", clientMasterRepository.find(1L).getClientName());
    }
    
    @Test   
    public void testDelete(){
        // get a CASClientMaster object from the repository
        ClientMaster clientMasterObjBeforeDel = clientMasterRepository.find(2L);
    
        // delete the ClientMaster object
        clientMasterRepository.delete(clientMasterObjBeforeDel);
    
        // get a ClientMaster object from the repository
        ClientMaster clientMasterObjAfterDel = clientMasterRepository.find(2L);
    
        // get the ClientMaster object ID 
        assertNull(clientMasterObjAfterDel);
    }
    
    @Test
    public void testFind(){
    
        // get a ClientMaster object from the repository
        ClientMaster clientMasterObj = clientMasterRepository.find(3L);             
    
        // compare the id's of passed and retrieved objects.
        assertThat(clientMasterObj.getId(), is(3L));
        assertTrue(clientMasterObj.getId() == 3);       
    }
    
    @Test
    public void testFindAll(){
        // get all ClientMaster object from the repository 
        List<ClientMaster> ClientMasterList = clientMasterRepository.findAll();             
    
        // check if it returns all records from DB
        assertTrue(ClientMasterList.size() > 0);
        assertThat(ClientMasterList.size(), is(4));
    }
    
    }
    

    When I execute above all test cases entirely, find & findAll test cases will be failed but pass when those executed individually. I am a newbie to testing framework. Let me know if there is anything wrong with above methodology to test the repository layer.

    UPDATE

    Even update test case is behaving strangely for some execution works properly in some it gives error as "NullPointerException" when i fetch the clientMaster object with find method.

    enter image description here

  • Amit
    Amit about 9 years
    ekuusela - thanks for quick reply...ya i know abt (at)Transactional annotation..but clarify something for me...so data persisted in (at)Before annotated method will rolled back for first test case or once all the test cases are executed....in tht case can u suggest the better to test the repository methods..i have checked many links tht i found but none addressed the issue i am facing..
  • ekuusela
    ekuusela about 9 years
    docs.spring.io/spring/docs/current/spring-framework-referenc‌​e/… . If a test is marked as (at)Transactional then it and the (at)Before method called before that test will run inside that transaction and any changes made in the test or the before method will be rolled back.
  • Amit
    Amit about 9 years
    ekuusela - thanks for your suggestions..i was able to resolve it by setting up a separate DB (HSQL) for testing...and setting hibernate.hbm2ddl.auto property to create-drop such that for every test execution i will have a fresh DB...correct me if i am wrong...since i have configured my application to use spring transactions if a test case is marked as transactional does the identity column value will be reset to initial value after roll back?? this was the issue for me identity column values doesnt seem to reset.....is this true..or am i missing something...