如何提高单元测试的覆盖率

一、定位未覆盖的代码

  1. ​利用 IDEA 的覆盖率工具​:

    • 右键测试类 → Run with Coverage ,或使用 Alt+Shift+F10(Windows)打开运行菜单选择覆盖率。
    • 查看高亮标记 :
      • 绿色:已覆盖代码行。
      • 红色:未覆盖代码行。
      • 黄色:部分覆盖(如条件分支未完全覆盖)。
  2. ​分析 JaCoCo 报告​:

    • 打开 target/site/jacoco/index.html,查看:
      • 行覆盖率(Line):哪些行未执行?
      • 分支覆盖率 (Branch):哪些条件分支(如 if/else)未覆盖?
      • 方法覆盖率:是否有未调用的方法?

二、针对性提升覆盖率的策略

策略 1:覆盖边界条件
  • 示例场景 :一个计算器类的方法 divide(int a, int b)。

    复制代码
    public int divide(int a, int b) {
        if (b == 0) throw new IllegalArgumentException("除数不能为0");
        return a / b;
    }
  • 问题 :常规测试可能只覆盖 b≠0 的情况,遗漏了异常分支。

  • 解决方案 :

    复制代码
    @Test
    void testDivideByZero() {
        Calculator calculator = new Calculator();
        assertThrows(IllegalArgumentException.class, () -> calculator.divide(5, 0));
    }
策略 2:覆盖所有代码分支
  • 示例场景 :带有 if-else 的逻辑。

    复制代码
    public String getGrade(int score) {
        if (score >= 90) return "A";
        else if (score >= 60) return "B";
        else return "C";
    }
  • 问题 :若仅测试 score=80,则未覆盖 score≥90 和 score<60 的分支。

  • 解决方案 :使用参数化测试覆盖所有分支:

    复制代码
    @ParameterizedTest
    @CsvSource({"95, A", "75, B", "50, C"})
    void testGetGrade(int score, String expected) {
        assertEquals(expected, grader.getGrade(score));
    }
策略 3:覆盖异常和错误处理
  • 示例场景 :数据库操作失败时的回滚逻辑。

    复制代码
    public void saveData(Data data) {
        try {
            database.insert(data);
        } catch (SQLException e) {
            logger.error("保存失败", e);
            rollback();
        }
    }
  • 问题 :正常流程测试不会触发 catch 块。

  • 解决方案 :使用 Mockito 模拟异常:

    复制代码
    @Test
    void testSaveDataFailure() {
        Database mockDb = mock(Database.class);
        when(mockDb.insert(any())).thenThrow(new SQLException());
        DataService service = new DataService(mockDb);
        
        service.saveData(new Data());
        verify(mockDb).rollback(); // 验证是否执行了回滚
    }
策略 4:覆盖工具生成的代码
  • 常见问题 :Lombok 生成的 getter/setter、equals/hashCode 或 IDE 自动生成的代码未覆盖。
  • 解决方案 :
    • 显式测试生成的代码(如验证 equals 方法)。

    • 配置 JaCoCo 忽略 Lombok 生成的代码(在 pom.xml 中):

      复制代码
      <configuration>
        <excludes>
          <exclude>​**​/*$Lombok*/​**​</exclude>
        </excludes>
      </configuration>

三、高级技巧

技巧 1:强制覆盖难以触发的代码
  • 场景 :测试 private 方法或静态代码块。

    复制代码
    public class ConfigLoader {
        static {
            loadConfig(); // 静态代码块
        }
        private static void loadConfig() { /* 加载配置 */ }
    }
  • 解决方案 :通过反射调用私有方法或触发静态初始化:

    复制代码
    @Test
    void testStaticBlock() throws Exception {
        Class.forName("com.example.ConfigLoader"); // 触发静态代码块
    }
技巧 2:优化测试数据
  • 使用随机测试工具 :如 QuickTheories 或 jqwik,生成大量随机输入覆盖边缘情况。

    复制代码
    @Property
    void testRandomInput(@ForAll int a, @ForAll int b) {
        assumeTrue(b != 0); // 忽略 b=0 的情况
        assertEquals(a / b, calculator.divide(a, b));
    }
技巧 3:忽略无需覆盖的代码
  • 配置 JaCoCo 排除 (在 pom.xml 中):

    复制代码
    <excludes>
      <exclude>​**​/model/*.java</exclude> // 忽略 POJO 类
      <exclude>​**​/Main.java</exclude>    // 忽略启动类
    </excludes>

四、避免常见误区

  1. ​盲目追求 100% 覆盖率​:

    • 某些代码(如自动生成的代码、简单 Getter)无需强制覆盖。
    • 更关注核心逻辑和复杂分支的覆盖。
  2. ​编写无效测试​:

    复制代码
    @Test
    void testAdd() {
        calculator.add(2, 3); // 没有断言!看似覆盖,实则无效
    }
  3. ​忽略测试代码质量​:

    • 避免重复代码:用 @BeforeEach 初始化公共对象。
    • 遵循命名规范:测试方法名应明确表达场景(如 testDivide_WhenDivisorIsZero_ThrowException)。

五、总结

通过以下步骤系统提升覆盖率:

  1. 定位未覆盖代码:使用 IDEA 高亮和 JaCoCo 报告。
  2. 设计针对性用例:覆盖边界条件、异常分支、复杂逻辑。
  3. 利用工具和技巧:参数化测试、Mock 异常、反射调用。
  4. 平衡覆盖率和成本:优先覆盖关键代码,忽略无关部分。
相关推荐
川石课堂软件测试2 天前
涨薪技术|0到1学会性能测试第9课-HTTP响应统计
数据库·功能测试·网络协议·http·kubernetes·单元测试·测试用例
我命由我123453 天前
SQL 检测脚本
java·数据库·sql·功能测试·单元测试·压力测试·可用性测试
神一样的老师6 天前
WS63 嵌入式 SSD1306 OLED 驱动单元测试实战
单元测试·log4j
CesareCheung6 天前
高级软件测试工程师面试锦集
面试·单元测试·压力测试
2501_915918417 天前
在 Xcode 中运行和调试单元测试的完整指南
ide·vscode·macos·ios·单元测试·个人开发·xcode
极小狐8 天前
MR 里测试摘要空白、覆盖率不显示?JUnit 与覆盖率配置 9 步排查
数据库·ci/cd·junit·单元测试·mr·devops·代码覆盖率
toooooop88 天前
FastAdmin(ThinkPHP 5.0)单元测试实践:从零到跑通
单元测试·fastadmin
silvamux_8 天前
大模型 API 单元测试怎么 mock 不误伤
单元测试·log4j·php
Helix2508 天前
Python单元测试实战:pytest框架从入门到企业级测试体系搭建指南
python·单元测试·实战·mock·pytest·测试覆盖率·fixture
2302_8057710710 天前
Day24:DDT+EXCEL数据驱动
功能测试·单元测试·自动化·测试用例·需求分析·web自动化