提问者:小点点

如何为try catch块编写junit?


我试图为下面的try-catch块编写junit,以提高代码的覆盖率。我已经得到了覆盖try块的测试,但是如何实现catch块呢?下面是带有try-catch块的代码,

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;
}

这就是我尝试覆盖捕获块的方法,但仍然覆盖了“尝试”块而不是“捕获”块

@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);
}

共1个答案

匿名用户

这里有一些事情发生。

首先,您在这个测试中创建的所有模拟都没有被注入到被测试的服务中,所以它们没有做任何事情。

其次,您从名为“session”的sessionfactory返回一个模拟,但是您在名为“mockSession”的模拟上的定义行为,请参见这两行:

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

第三,我怀疑您的测试类已经有了一个已配置的< code>baseDaoImpl,其中注入了mocks,否则它会在几个地方抛出npe。您要做的是在这些模拟上进行配置。如果您要在其他测试中使用reset返回其他模拟实例,那么您需要在全局SessionFactory mock上使用reset。

这是一个完整的测试类,我相信你的baseDaoImpl是什么样子的。它包括我知道的所有导入,我不知道您正在使用哪个 Session、SessionFactory 或 SQLQuery 类。

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());
    }
}