Mocking Hibernate DAOs to test Service Level Spring Beans

A simple layered architecture usually consists of a view layer, a service layer and domain layer. DAO’s are also placed at the domain layer together with the domain objects. Only the upper layer is aware of the lower layer and the interaction happens from top to bottom. A well known example might be JSF-Spring-Hibernate where spring beans are injected to JSF managed beans and these service level spring beans are used to interact with hibernate(HibernateTemplate).

Testing the DAO’s is fairly simple using the spring’s AbstractBlaBlaSomeFancyNameTestCases, actually the fun part is testing the service level business objects(in this case a spring bean). Assume we are trying to save a Customer object to the db and view layer makes a call to the service object. Later after doing a check, service bean makes a call to the DAO layer. Following stuff is needed;

* ICustomerDAO
* CustomerDAO
* IBusinessService
* BusinessService
* Customer

The whole idea is to do a simple check to see whether the customer is already saved or not. If the customer is already in db, a business rule exception is thrown.

ICustomerDAO

    
    

package domain;

public interface ICustomerDAO {
  public void save(Customer customer);
  public boolean isAlreadySaved(Customer customer);
}      

CustomerDAO

  
    
    

package domain;

import java.util.List;

import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

public class CustomerDAO extends HibernateDaoSupport implements ICustomerDAO{

  public void save(Customer customer){
    getHibernateTemplate().save(customer);
  }

  public boolean isAlreadySaved(Customer customer) {
    //Some algorithm to do the check here
  }

}      

IBusinessService

  
    
    

package service;

import exceptions.BusinessRuleException;
import domain.Customer;

public interface IBusinessService {
  public void saveCustomer(Customer customerthrows BusinessRuleException;
}      

BusinessService

  
    
    

package service;

import exception.BusinessRuleException;
import domain.ICustomerDAO;
import domain.Customer;

public class BusinessService implements IBusinessService{

  private ICustomerDAO customerDAO;

  public void saveCustomer(Customer customerthrows BusinessRuleException{
    if(customer == null || getCustomerDAO().isAlreadySaved(customer))
      throw new BusinessRuleException();
    else
      getCustomerDAO().save(customer);
  }

  public ICustomerDAO getCustomerDAO() {
    return customerDAO;
  }

  public void setCustomerDAO(ICustomerDAO customerDAO) {
    this.customerDAO = customerDAO;
  }

}      

Finally the fun part, testing the BusinessService;

BusinessServiceTest

  
    
    

package service;

import org.jmock.Mock;
import org.jmock.MockObjectTestCase;

import exception.BusinessRuleException;

import domain.ICustomerDAO;
import domain.Customer;

public class BusinessServiceTest extends MockObjectTestCase {

  private BusinessService businessService;

  private ICustomerDAO customerDAO;

  private Mock mockCustomerDAO;

  protected void setUp() throws Exception {
    businessService = new BusinessService();

    mockCustomerDAO = new Mock(ICustomerDAO.class);
    customerDAO = (ICustomerDAO)mockCustomerDAO.proxy();
    businessService.setCustomerDAO(customerDAO);
  }

  public void testTryingToSaveACustomerThatIsAlreadyInDBCausesBusinessRuleException() {
    mockCustomerDAO.expects(once()).method(“isAlreadySaved”).will(returnValue(true));
    try {
      businessService.saveCustomer(new Customer());
      fail();
    }catch(BusinessRuleException businessRuleException) {
      //test passes
    }
  }

  public void testTryingToSaveACustomerThatIsNullCausesBusinessRuleException() {
    try {
      businessService.saveCustomer(null);
      fail();
    }catch(BusinessRuleException businessRuleException) {
      //test passes
    }
  }

}      

That’s all, the service object uses a DAO that actually hits the db. In order to test it, I’ve replaced it a mock version. The example is a simple case, but the idea remains same for more complex business rules. The good practice is to make these kind of checks at service layer instead of at DAO. Although I’ve used spring-hibernate as an example, the practice applies to all kind of architectures containing a business layer.

About these ads

2 Responses to Mocking Hibernate DAOs to test Service Level Spring Beans

  1. Alessio Pace says:

    Hi,
    I agree with you, but personally I prefer using EasyMock (http://www.easymock.org) over JMock (basically because it allows compiler checks and refactoring on expected methods, which are not referenced simply by a string), and using a generic dao (http://forum.springframework.org/showthread.php?t=25160) instead of a single dao for each entity.
    What do you think?

  2. Cagatay says:

    Well, easymock vs jmock is subject to discussion. I usually use jmock just because I got used to it:). Generic DAO is also the approach I usually follow but sometimes I prefer domain specific daos when there are domain specific requirements to keep the generic dao simple and decoupled from entities.

Follow

Get every new post delivered to your Inbox.

Join 106 other followers

%d bloggers like this: