You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用JUnit的@Test(expected = SQLException.class)覆盖方法的catch代码块?

如何测试getId方法的catch代码块(及为什么@Test(expected = SQLException.class)直接用不了)

嘿,我来帮你理清楚这个问题~首先得明确一个核心点:你的getId方法并没有把捕获到的SQLException重新抛出——它只是在catch块里打了日志就结束了。所以直接用@Test(expected = SQLException.class)是不会生效的,因为异常已经被方法内部“吞掉”了,测试方法根本接收不到这个异常。

那怎么才能覆盖到catch代码块呢?我们需要用Mock框架(比如Mockito)模拟JDBC操作抛出SQLException,然后验证catch块里的逻辑是否正确执行。下面是具体的步骤和示例:

步骤1:明确测试目标

我们要验证的是:当JDBC操作抛出SQLException时,方法会记录指定的错误日志,并且返回默认值0。

步骤2:用Mockito编写测试用例

假设你的类名为ManagerDao,我们需要Mock它的DataSource依赖,模拟获取连接或执行SQL时抛出异常:

import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import org.slf4j.Logger;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.*;

@RunWith(MockitoJUnitRunner.class)
public class ManagerDaoTest {

    // Mock数据源,模拟JDBC操作
    @Mock
    private DataSource dataSource;

    @Mock
    private Connection connection;

    @Mock
    private PreparedStatement preparedStatement;

    // Mock日志对象,用于验证是否输出了预期日志
    @Mock
    private Logger logger;

    // 注入Mock对象到目标测试类
    @InjectMocks
    private ManagerDao managerDao;

    @Test
    public void getId_WhenSQLExceptionOccurs_ShouldLogErrorAndReturnZero() throws SQLException {
        // 1. 模拟数据源获取连接时抛出SQLException
        when(dataSource.getConnection()).thenThrow(new SQLException("Test SQL Exception"));

        // 2. 执行目标方法
        int result = managerDao.getId("testCol1", 123, "testCol3");

        // 3. 验证方法是否返回默认值0
        assertEquals(0, result);

        // 4. 验证catch块中的日志是否被正确记录
        verify(logger).error("ERROR-WARNING:<<<getId():: ID testCol1 SQLException occurred while selecting data table.");
    }
}

为什么不能直接用@Test(expected = SQLException.class)?

因为你的getId方法在catch块中捕获了SQLException,没有重新抛出它(也没有包装成其他异常抛出)。这意味着异常在方法内部就被处理了,不会传播到测试方法中,所以@Test(expected)会因为没捕获到预期异常而失败。

如果一定要用@Test(expected)的方式,你需要修改原方法,让它重新抛出异常,比如:

catch (SQLException e) {
    logger.error("ERROR-WARNING:<<<getId():: ID "+col1+" SQLException occurred while selecting data table.");
    throw e; // 重新抛出SQLException
}

或者包装成自定义异常抛出:

catch (SQLException e) {
    logger.error("ERROR-WARNING:<<<getId():: ID "+col1+" SQLException occurred while selecting data table.");
    throw new DatabaseDownException("Database error", e); // 假设DatabaseDownException是你的自定义异常
}

但这样修改需要评估是否符合你的业务逻辑,毕竟原方法设计是吞掉异常返回默认值。

补充:如果日志是静态获取的怎么办?

如果你的日志是通过LoggerFactory.getLogger(ManagerDao.class)静态获取的,那需要用PowerMock来模拟静态方法:

import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.sql.DataSource;
import java.sql.SQLException;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.*;

@RunWith(PowerMockRunner.class)
@PrepareForTest(ManagerDao.class) // 声明要Mock静态方法的类
public class ManagerDaoTest {

    @Mock
    private DataSource dataSource;

    @Mock
    private Logger mockLogger;

    @Test
    public void getId_WhenSQLExceptionOccurs_ShouldLogError() throws SQLException {
        // 模拟静态LoggerFactory返回Mock的日志对象
        PowerMockito.mockStatic(LoggerFactory.class);
        when(LoggerFactory.getLogger(ManagerDao.class)).thenReturn(mockLogger);

        // 模拟抛出SQLException
        when(dataSource.getConnection()).thenThrow(new SQLException("Test error"));

        // 执行方法
        int result = managerDao.getId("test", 1, "test");

        // 验证返回值和日志
        assertEquals(0, result);
        verify(mockLogger).error(contains("SQLException occurred while selecting data table"));
    }
}

内容的提问来源于stack exchange,提问作者Arpan Paliwal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 09:44:31