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它 - mock
DataUtil.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
相关产品推荐
相关产品推荐

