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

Java单元测试:如何覆盖getAll方法的else与catch分支提升Jacoco覆盖率

问题描述

我已经完成了SomeService类中getAll方法的开发,但Jacoco报告显示该方法的else代码块和catch代码块未被单元测试覆盖。我尝试编写测试用例覆盖else分支,期望让resultSet为空从而触发else逻辑,但当前的Mock方式无效,达不到预期效果。同时我也需要覆盖catch分支,以实现99%的Java代码覆盖率,请问该如何实现?

原方法代码

public class SomeService {
    
    public List<Something> getAll() throws SomeCustomException {
        List<Something> listOfSomething = new ArrayList<>();
        try (Data data = DataUtil.get(Constants.SOME_TABLE_NAME)){
            ResultSet resultSet = data.retrieveAll();
            if(resultSet != null && !resultSet.isEmpty()){
                Something something;
                for (ResultSetRow row : resultSet){
                    something = new Something();
                    something.setX(row.get("someColumnX"));
                    //...
                    listOfSomething.add(something);
                }
            }else{
                throw new SomeCustomException("ResultSet is null");
            }
        }catch (ExceptionOne | ExceptionTwo e){
            throw new SomeCustomException(e.getMessage(), e);
        }
        return listOfSomething;
    }
    
}

我的测试代码(无效)

@Test
void getAllReturnsEmpty() {
    SomeService someServiceMock = mock(SomeService.class);
    ResultSet resultSetMock = mock(ResultSet.class);
    when(!resultSetMock.isEmpty).thenReturn(false);
    
    assertThat(someServiceMock.getAll().isEmpty()).isTrue();
}
解决方案

一、覆盖else代码块

你当前测试无效的核心问题是mock了SomeService本身,调用getAll()时执行的是mock的空实现,根本不会走到真实的方法逻辑里。正确的做法是:

  • 直接创建SomeService的真实实例,不要mock它
  • mockDataUtil.get()静态方法,让它返回一个mock的Data对象
  • 让mock的Data返回null或空的ResultSet,触发else分支

示例测试代码(基于Mockito+AssertJ):

import static org.mockito.Mockito.*;
import static org.junit.jupiter.api.Assertions.*;
import static org.assertj.core.api.Assertions.*;

@Test
void getAllThrowsWhenResultSetNullOrEmpty() {
    // 静态mock DataUtil类
    try (MockedStatic<DataUtil> mockedDataUtil = mockStatic(DataUtil.class)) {
        // 创建mock的Data对象
        Data mockData = mock(Data.class);
        // 指定DataUtil.get返回mockData
        mockedDataUtil.when(() -> DataUtil.get(Constants.SOME_TABLE_NAME)).thenReturn(mockData);
        
        // 场景1:ResultSet为null
        when(mockData.retrieveAll()).thenReturn(null);
        assertThrows(SomeCustomException.class, () -> new SomeService().getAll());
        
        // 场景2:ResultSet为空集合
        ResultSet emptyResultSet = mock(ResultSet.class);
        when(emptyResultSet.isEmpty()).thenReturn(true);
        when(mockData.retrieveAll()).thenReturn(emptyResultSet);
        
        SomeCustomException exception = assertThrows(SomeCustomException.class, () -> new SomeService().getAll());
        assertThat(exception.getMessage()).isEqualTo("ResultSet is null");
    }
}

二、覆盖catch代码块

要触发catch分支,需要让DataUtil.get()或data.retrieveAll()抛出ExceptionOne/ExceptionTwo,分两种场景实现:

场景1:DataUtil.get()抛出异常

@Test
void getAllThrowsWhenDataUtilFails() {
    try (MockedStatic<DataUtil> mockedDataUtil = mockStatic(DataUtil.class)) {
        // 指定DataUtil.get抛出ExceptionOne
        mockedDataUtil.when(() -> DataUtil.get(Constants.SOME_TABLE_NAME))
                .thenThrow(new ExceptionOne("获取数据连接失败"));
        
        SomeCustomException exception = assertThrows(SomeCustomException.class, () -> new SomeService().getAll());
        assertThat(exception.getCause()).isInstanceOf(ExceptionOne.class);
        assertThat(exception.getMessage()).isEqualTo("获取数据连接失败");
    }
}

场景2:data.retrieveAll()抛出异常

@Test
void getAllThrowsWhenRetrieveAllFails() {
    try (MockedStatic<DataUtil> mockedDataUtil = mockStatic(DataUtil.class)) {
        Data mockData = mock(Data.class);
        mockedDataUtil.when(() -> DataUtil.get(Constants.SOME_TABLE_NAME)).thenReturn(mockData);
        
        // 指定retrieveAll抛出ExceptionTwo
        when(mockData.retrieveAll()).thenThrow(new ExceptionTwo("查询数据失败"));
        
        SomeCustomException exception = assertThrows(SomeCustomException.class, () -> new SomeService().getAll());
        assertThat(exception.getCause()).isInstanceOf(ExceptionTwo.class);
        assertThat(exception.getMessage()).isEqualTo("查询数据失败");
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 18:05:19