Home > OS >  How to write junit for try catch block?
How to write junit for try catch block?

Time:12-24

I'm trying to write junit for the following try-catch block to improve coverage of the code. I've got the test to cover try block, but how do do it for catch block? Following is the code with try-catch block,

public boolean testDb() {
        boolean dbHealth = true;
    try {
        Session session = sessionFactory.getCurrentSession();
        SQLQuery sqlQuery = session.createSQLQuery("SELECT empId from employee");
        sqlQuery.executeUpdate();
    } catch (Exception e) {
        dbHealth = false;
        LOG.error(e);
    }
    return dbHealth;
}

This is what I tried for the coverage of catch block, but still 'try' block is getting covered instead of 'catch' block

@Test
public void testDb_throwException() {
  SessionFactory sessionFactory = mock(SessionFactory.class);
  Session session= mock(Session.class);
  Query query = mock(Query.class);
  when(sessionFactory.getCurrentSession()).thenReturn(session);
  when(sessionFactory.openSession()).thenReturn(session);
  when(mockSession.createSQLQuery(Mockito.anyString())).thenReturn(query);
  when(query.executeUpdate()).thenThrow(new RuntimeException("sql exception"));
  boolean res= baseDaoImpl.testDatabaseHealth();
  Assert.assertTrue(res);
}

CodePudding user response:

There's a few things going on here.

First, All of the mocks that you're creating in this test aren't being injected into the service under test, so they aren't doing squat.

Second, you're returning a mock from the sessionfactory named, "session", but your defining behavior on a mock named, "mockSession", see these two lines:

when(sessionFactory.openSession()).thenReturn(session);
when(mockSession.createSQLQuery(Mockito.anyString())).thenReturn(query);

Third, I suspect that your test class already has a configured baseDaoImpl, with mocks injected into it, otherwise it would be throwing NPEs in a few places. What you want to do is configure on those mocks. You'll want to use reset on the global SessionFactory mock if you're going to be using it to return other mocked instances in other tests.

Here's a full test class with what I believe your baseDaoImpl to look like. It includes all the imports that I know of, I don't know which Session, SessionFactory, or SQLQuery class you're using.

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

@ExtendWith(MockitoExtension.class)
class BaseDaoImplTest {

    @Mock // mock the session factory
    SessionFactory sessionFactory;

    @InjectMocks // inject the mock into the baseDao
    BaseDaoImpl baseDao;

    @Test
    void somethingToTest() {
        // define query mock to throw exception
        SQLQuery sqlQuery = mock(SQLQuery.class);  // your class actually returns an SQLQuery, so you need to mock this and not the interface
        when(sqlQuery.executeUpdate()).thenThrow(new RuntimeException("sql exception"));

        // define session mock to return the sqlQuery mock created above
        Session session = mock(Session.class);
        when(session.createSQLQuery(anyString())).thenReturn(sqlQuery);

        // instruct the session factory mock that's injected into your class under test to return the session created above
        when(sessionFactory.getCurrentSession()).thenReturn(session);

        assertFalse(baseDao.somethingToTest());
    }

    @Test
    void somethingToTest_condensedVersion() {
        // since all your want to test is that the catch block behaves properly,
        // instruct the session factory mock to throw an exception
        when(sessionFactory.getCurrentSession()).thenThrow(new RuntimeException());

        assertFalse(baseDao.somethingToTest());
    }
}
  • Related