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

Java中SQLTimeoutException场景的JUnit编写与Sonar代码覆盖方案

问题描述

现有一段从MariaDB获取记录的Java代码,需针对SQLTimeoutException业务场景实现测试并达成Sonar代码覆盖。代码示例如下:

业务方法代码

public SFVCustomerDetails findDetailsWithCIFNumber(String cifNumber) {
    SFVCustomerDetails details = null;
    try {
        details = sfvDetailsDao.findDetailsWithCIFNumber(cifNumber);
    } catch (Exception ex) {
        handleSQLException(ex);
    }
    return details;
}

异常处理方法代码

public void handleSQLException(Exception exception) {
    log.info("handleException()==>" + exception.getMessage());
    List<ServiceError> errorList;
    if (exception instanceof SQLTimeoutException) {
        errorList = CommonUtils.prepareErrorList(ErrorCodeEnum.IAL_DB_TIMEOUT);
    } else {
        errorList = CommonUtils.prepareErrorList(ErrorCodeEnum.IAL_DB_GENERIC_FAILURE);
    }
    throw new IALException(errorList, new BaseRequest(), null);
}

请问如何编写该场景的JUnit用例并实现Sonar代码覆盖?


解决方案

可以通过Mockito模拟DAO层抛出指定异常,结合JUnit编写测试用例,覆盖SQLTimeoutException分支及异常处理逻辑,具体步骤如下:

1. 依赖准备

确保测试依赖包含JUnit 5、Mockito核心库及mockito-junit-jupiter(用于集成JUnit 5与Mockito)。

2. 编写测试类

核心思路

  • 模拟sfvDetailsDao对象,使其调用findDetailsWithCIFNumber时抛出SQLTimeoutException
  • 调用目标业务方法,捕获抛出的IALException
  • 验证异常中的错误码是否符合预期,同时确认分支逻辑被执行

测试代码示例

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 java.sql.SQLTimeoutException;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;

@ExtendWith(MockitoExtension.class)
class YourServiceClassTest { // 替换为实际业务类名

    @Mock
    private SFVDetailsDao sfvDetailsDao; // 模拟DAO对象

    @InjectMocks
    private YourServiceClass service; // 注入目标业务类实例

    @Test
    void findDetailsWithCIFNumber_SQLTimeoutExceptionThrown_ThrowsIALExceptionWithTimeoutCode() {
        // 1. 准备测试数据
        String testCif = "CIF123456";
        SQLTimeoutException timeoutEx = new SQLTimeoutException("DB query timed out");

        // 2. 模拟DAO抛出超时异常
        doThrow(timeoutEx).when(sfvDetailsDao).findDetailsWithCIFNumber(testCif);

        // 3. 调用方法并捕获异常
        IALException thrownEx = assertThrows(IALException.class, () -> {
            service.findDetailsWithCIFNumber(testCif);
        });

        // 4. 验证异常错误码
        assertNotNull(thrownEx.getErrorList());
        assertEquals(ErrorCodeEnum.IAL_DB_TIMEOUT, thrownEx.getErrorList().get(0).getErrorCode());

        // 5. 验证DAO方法被调用
        verify(sfvDetailsDao, times(1)).findDetailsWithCIFNumber(testCif);
    }

    // 补充通用DB异常分支测试,实现全分支覆盖
    @Test
    void findDetailsWithCIFNumber_GenericExceptionThrown_ThrowsIALExceptionWithGenericCode() {
        String testCif = "CIF123456";
        Exception genericEx = new Exception("Generic DB failure");

        doThrow(genericEx).when(sfvDetailsDao).findDetailsWithCIFNumber(testCif);

        IALException thrownEx = assertThrows(IALException.class, () -> {
            service.findDetailsWithCIFNumber(testCif);
        });

        assertEquals(ErrorCodeEnum.IAL_DB_GENERIC_FAILURE, thrownEx.getErrorList().get(0).getErrorCode());
        verify(sfvDetailsDao, times(1)).findDetailsWithCIFNumber(testCif);
    }
}

3. 达成Sonar代码覆盖

  • 上述测试用例覆盖了findDetailsWithCIFNumber的try-catch分支,以及handleSQLException中SQLTimeoutException和通用异常两个分支
  • 运行测试后,Sonar会识别到所有分支已被覆盖,解决代码覆盖不足的问题

关键注意事项

  • 确保sfvDetailsDao被正确模拟,避免触发真实数据库操作
  • 捕获IALException后需验证错误码,确保异常处理逻辑符合预期
  • 必须补充通用异常分支的测试,实现全分支覆盖以满足Sonar的代码覆盖要求

内容的提问来源于stack exchange,提问作者rajkumar singh

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 08:01:23