3

This is my class which need to be tested:

@Repository
@Transactional
public class ProductDAOImpl implements ProductDAO {

private static final Logger logger = Logger.getLogger(ProductDAOImpl.class);

@Autowired
private SessionFactory hibernateSessionFactory;


@Override
public ProductDTO getProduct(String isbn) throws ProductException {
    ProductDTO productDTO = new ProductDTO();
    Product product = getProductFromDb(isbn);
    BeanUtils.copyProperties(product, productDTO);
    return productDTO;
}

private Product getProductFromDb(String isbn) throws ProductException{
    Session session = this.hibernateSessionFactory.getCurrentSession();


    String hql = "FROM com.esp.dao.entity.Product P WHERE P.isbn13 = :isbn13";
    Query query = session.createQuery(hql);
    query.setParameter("isbn13",isbn);


    List<Product> productList = query.list();  // Want to mock this call
    if(productList.size() ==1)      
        return productList.get(0);
    else if(productList.size() >1)
        // throw new ProductException("Cannot return product. Multiple products found.", HttpServletResponse.SC_NOT_FOUND);
        throw new ProductException("Cannot return product. Multiple products found.");
    else if(productList.size() == 0){
        throw new ProductException("Cannot return product. No products found.");
    }
    return null;

}

I want to mock the query.list() method. This is what I have tried so far but getting exception: Type 'SessionFactory' is an interface and it cannot be spied on.

@RunWith(MockitoJUnitRunner.class)
public class TestProductDaoImpl {

@Spy
private SessionFactory hibernateSessionFactory;
@InjectMocks
private ProductDAOImpl productDAOImpl;

@Test
public void testGetProduct() throws ProductException {

    Session session = this.hibernateSessionFactory.getCurrentSession();

    String hql = "";
    Query query = session.createQuery(hql);
    Query spy = Mockito.spy(query);
    List<Product> productList = getProductList();
    doReturn(productList).when(spy).list();

    productDAOImpl.getProduct("abc");


}

I can mock the getProductFromDb(). But in that case there is no need to write a test case for that as the maximum part of the class is getting mocked.

2 Answers 2

7

In my opinion there are two approach:

First: Create mock on SessionFactory like this

@Mock
private SessionFactory hibernateSessionFactory;

@Before
public void beforeTest(){
    MockitoAnnotations.initMocks(this);
}

@Test
public void testGetProduct() throws ProductException {
     //then mock all you need from hibernateSessionFactory
     Session session = Mockito.mock(Session.class);
     Query query = Mockito.mock(Query.class);

     Mockito.when(hibernateSessionFactory.getCurrentSession()).thenReturn(session);
     Mockito.when(session.createQuery("FROM com.esp.dao.entity.Product P WHERE P.isbn13 = :isbn13")).thenReturn(query);

     List<Product> productList = new ArrayList<>(1);
     Mockito.when(query.list()).thenReturn(productList);

Second: You should create instance of SessionFactory

private SessionFactory hibernateSessionFactory;

@Before
public void beforeTest(){
    hibernateSessionFactory = Mockito.spy(new ConstructorForSessionFactory ());
}
Sign up to request clarification or add additional context in comments.

8 Comments

I am sorry. I just edited my question. I need to mock the Query.list() method. For that in my test class I need to create a valid Query object & then mock it. But here I am unable to mock the Query object.
@Sumit Pal. You don't have error 'Type 'SessionFactory' is an interface and it cannot be spied on' and problem with only 'query.list()'?
I have that error. By applying your solution 1 it solved & now I am getting NullPointerException at line session.createQuery(hql);
The reason I am spying the hibernateSessionFactory is that hibernateSessionFactory is autoWired in the ProductDAOImpl. But I also need a real hibernateSessionFactory object to create Query object in the test class (so that I can mock it). Please correct me If I am wrong. I am new to Mockito
Thanks!!. I was not aware that we can mock like Mockito.mock(Session.class); I thought we have to pass a valid object of Session in Mockito.mock(). :)
|
1

We can perform the unit tests for Hibernate query.list. if we have the following method to get the list of results from database:

private List<?> getTxns(String sql) {
    Session session = null;
    try {
        session = ht.getSessionFactory().openSession();
        Query q = session.createSQLQuery(sql).addEntity(Entity.class);
        return q.list();
    } catch (Exception e) {
        log.error(sql, e);
    } finally {
        daoUtil.closeSession(sql, session);
    }

    return new ArrayList();
}

Then we can write the following way for unit testing :

@BeforeEach
public void setup() {
    SessionFactory sessionFactory = mock(SessionFactory.class);
    hibernateTemplate = mock(HibernateTemplate.class);
    when(daoUtil.getWritableHT()). thenReturn(hibernateTemplate);
    when(hibernateTemplate.getSessionFactory()).thenReturn(sessionFactory);
    Session session= mock(Session.class);
    when(sessionFactory.openSession()).thenReturn(session);
    SQLQuery sqlQuery=mock(SQLQuery.class);
    when(session.createSQLQuery(any())).thenReturn(sqlQuery);
    when(sqlQuery.addEntity(Entity.class)).thenReturn(sqlQuery);
    Entity entity = new Entity();
    List<Entity> entityList= new ArrayList<>();
    entityList.add(txn);
    when(sqlQuery.list()).thenReturn(entityList);
}

 @Test
void getTxn_list() {
    //Arrange and Assert
    Assert.assertEquals(1,object.getTxns(query).size());

}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.