如何为Spring Boot Service的updateCar方法实现单元测试全覆盖
Spring Boot Service updateCar方法单元测试全覆盖方案
问题背景
我正在为Spring Boot Service编写单元测试,希望实现updateCar方法的全覆盖。
目标方法(updateCar)
public void updateCar(String id, String carModel, Integer HP, Integer year, String designer) { Garage garage = garageRepository.findById(id) .orElseThrow(() -> new IllegalStateException( "A car with the id " + id + " is not in our Garage.")); if(carModel != null && carModel.length() > 0 && !Objects.equals(garage.getCarModel(), carModel)) { garage.setCarModel(carModel); } if(HP != null && !Objects.equals(garage.getHP(), HP)) { garage.setHP(HP); } if(year != null && !Objects.equals(garage.getYear(), year)) { garage.setYear(year); } if(designer != null && designer.length() > 0 && !Objects.equals(garage.getDesigner(), designer)) { garage.setDesigner(designer); } garageRepository.save(garage); }
当前测试代码
@Test @DisplayName("Update Car Test") void testUpdateCar() { Garage updatedGarage = new Garage(); String id = "630ca281f12905d5f5249f08"; String carModel = "Updated carModel"; int HP = 480; int year = 1964; String designer = "Updated designer"; updatedGarage.setId(id); updatedGarage.setCarModel(carModel); updatedGarage.setHP(HP); updatedGarage.setYear(year); updatedGarage.setDesigner(designer); when(garageRepository.findById(id)) .thenReturn(Optional.of(updatedGarage)); garageService.updateCar(id, carModel, HP, year, designer); when(garageRepository.save(updatedGarage)) .thenReturn(updatedGarage); verify(garageRepository).findById(id); }
当前问题
当前测试仅获得部分覆盖率,未覆盖updateCar方法中的garage.setCarModel(carModel)、garage.setHP(HP)、garage.setYear(year)以及garage.setDesigner(designer)逻辑,请问如何实现该方法的测试全覆盖?
全覆盖测试方案
要覆盖所有分支逻辑,需要针对每个字段的更新条件、不更新条件,以及findById返回空的异常场景分别编写测试用例。
1. 覆盖字段更新的核心场景
当前测试中传入的参数和模拟的Garage对象原有值完全一致,导致if条件不成立,自然不会执行set方法。需要让传入的参数和原有值不同:
@Test @DisplayName("Update all fields successfully when values are different") void testUpdateAllFields() { // 初始化原有车库对象,设置初始值 String id = "630ca281f12905d5f5249f08"; Garage existingGarage = new Garage(); existingGarage.setId(id); existingGarage.setCarModel("Original Model"); existingGarage.setHP(300); existingGarage.setYear(1960); existingGarage.setDesigner("Original Designer"); // 模拟Repository返回原有对象 when(garageRepository.findById(id)).thenReturn(Optional.of(existingGarage)); // 传入不同的更新参数 String newModel = "Updated carModel"; Integer newHP = 480; Integer newYear = 1964; String newDesigner = "Updated designer"; garageService.updateCar(id, newModel, newHP, newYear, newDesigner); // 验证每个字段都被正确更新 assertEquals(newModel, existingGarage.getCarModel()); assertEquals(newHP, existingGarage.getHP()); assertEquals(newYear, existingGarage.getYear()); assertEquals(newDesigner, existingGarage.getDesigner()); // 验证save方法被调用 verify(garageRepository).save(existingGarage); }
2. 覆盖字段不更新的分支场景
针对每个字段的if条件不成立的情况(参数为空、空字符串、与原有值相同),分别编写测试:
针对carModel的不更新测试
@Test @DisplayName("Do not update carModel when new value matches original") void testNotUpdateCarModelWhenSame() { String id = "630ca281f12905d5f5249f08"; Garage existingGarage = new Garage(); existingGarage.setId(id); String originalModel = "Original Model"; existingGarage.setCarModel(originalModel); when(garageRepository.findById(id)).thenReturn(Optional.of(existingGarage)); // 传入和原有值相同的carModel garageService.updateCar(id, originalModel, null, null, null); // 验证carModel未被修改 assertEquals(originalModel, existingGarage.getCarModel()); verify(garageRepository).save(existingGarage); } @Test @DisplayName("Do not update carModel when new value is empty string") void testNotUpdateCarModelWhenEmpty() { String id = "630ca281f12905d5f5249f08"; Garage existingGarage = new Garage(); existingGarage.setId(id); existingGarage.setCarModel("Original Model"); when(garageRepository.findById(id)).thenReturn(Optional.of(existingGarage)); // 传入空字符串 garageService.updateCar(id, "", null, null, null); assertEquals("Original Model", existingGarage.getCarModel()); verify(garageRepository).save(existingGarage); }
针对HP的不更新测试
@Test @DisplayName("Do not update HP when new value matches original") void testNotUpdateHPWhenSame() { String id = "630ca281f12905d5f5249f08"; Garage existingGarage = new Garage(); existingGarage.setId(id); Integer originalHP = 300; existingGarage.setHP(originalHP); when(garageRepository.findById(id)).thenReturn(Optional.of(existingGarage)); garageService.updateCar(id, null, originalHP, null, null); assertEquals(originalHP, existingGarage.getHP()); verify(garageRepository).save(existingGarage); } @Test @DisplayName("Do not update HP when new value is null") void testNotUpdateHPWhenNull() { String id = "630ca281f12905d5f5249f08"; Garage existingGarage = new Garage(); existingGarage.setId(id); existingGarage.setHP(300); when(garageRepository.findById(id)).thenReturn(Optional.of(existingGarage)); garageService.updateCar(id, null, null, null, null); assertEquals(300, existingGarage.getHP()); verify(garageRepository).save(existingGarage); }
同理,为year和designer编写上述类似的不更新场景测试即可覆盖对应分支。
3. 覆盖找不到车辆的异常场景
@Test @DisplayName("Throw exception when car not found by id") void testUpdateCarNotFound() { String id = "non-existent-id"; when(garageRepository.findById(id)).thenReturn(Optional.empty()); // 验证抛出指定异常 IllegalStateException exception = assertThrows(IllegalStateException.class, () -> { garageService.updateCar(id, "New Model", 500, 2020, "New Designer"); }); assertEquals("A car with the id " + id + " is not in our Garage.", exception.getMessage()); // 验证save方法未被调用 verify(garageRepository, never()).save(any(Garage.class)); }
4. 混合场景测试(部分字段更新)
测试部分字段更新、部分不更新的情况,确保逻辑兼容:
@Test @DisplayName("Update only partial fields") void testUpdatePartialFields() { String id = "630ca281f12905d5f5249f08"; Garage existingGarage = new Garage(); existingGarage.setId(id); existingGarage.setCarModel("Original Model"); existingGarage.setHP(300); existingGarage.setYear(1960); existingGarage.setDesigner("Original Designer"); when(garageRepository.findById(id)).thenReturn(Optional.of(existingGarage)); // 只更新HP和year,其他参数保持原有值或为空 Integer newHP = 480; Integer newYear = 1964; garageService.updateCar(id, "Original Model", newHP, newYear, ""); // 验证HP和year被更新,其他字段不变 assertEquals("Original Model", existingGarage.getCarModel()); assertEquals(newHP, existingGarage.getHP()); assertEquals(newYear, existingGarage.getYear()); assertEquals("Original Designer", existingGarage.getDesigner()); verify(garageRepository).save(existingGarage); }
内容的提问来源于stack exchange,提问作者WorkWork
相关产品推荐
相关产品推荐

