Spring Boot嵌套服务测试:注册乘客到行程方法报错解决咨询
解决方案
问题根源
你的测试代码直接用UUID.randomUUID()生成了乘客ID和行程ID,但registerPassengerToTrip方法内部会先校验这两个实体是否存在——此时无论是真实数据库还是Mock的Repository里都没有对应ID的乘客/行程,因此抛出了ValidationException。
下面分两种测试场景给出解决方法:
场景1:单元测试(Mock依赖)
必须Mock PassengerRepository和TripRepository,单元测试的核心是隔离RegistrationService的依赖,只测试它的业务逻辑,不需要真实数据库操作。
修改后的测试代码示例:
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.util.Optional; import java.util.UUID; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @ExtendWith(MockitoExtension.class) public class RegistrationServiceTest { @Mock private PassengerRepository passengerRepository; @Mock private TripRepository tripRepository; @Mock private RegistrationRepository registrationRepository; @InjectMocks private RegistrationService registrationService; @Test public void whenRegisterPassengerToTrip_thenReturnPassInTrip(){ // prepare UUID passengerId = UUID.randomUUID(); UUID tripId = UUID.randomUUID(); Integer seatNumber = 5; // 模拟数据库中存在对应ID的乘客和行程 Passenger mockPassenger = new Passenger(); mockPassenger.setId(passengerId); when(passengerRepository.findById(passengerId)).thenReturn(Optional.of(mockPassenger)); Trip mockTrip = new Trip(); mockTrip.setId(tripId); when(tripRepository.findById(tripId)).thenReturn(Optional.of(mockTrip)); // 模拟保存PassInTrip的返回值(按需配置) PassInTrip mockPassInTrip = new PassInTrip(); mockPassInTrip.setPassenger(mockPassenger); mockPassInTrip.setTrip(mockTrip); mockPassInTrip.setSeatNumber(seatNumber); when(registrationRepository.save(any(PassInTrip.class))).thenReturn(mockPassInTrip); // testing PassInTrip passInTrip = registrationService.registerPassengerToTrip(passengerId, tripId, seatNumber); // validate verify(registrationRepository).save(any()); assert passInTrip.getSeatNumber().equals(seatNumber); } }
关键操作:
- 用
@Mock创建PassengerRepository、TripRepository的Mock实例 - 用
@InjectMocks将Mock依赖注入到RegistrationService中 - 通过
when(...).thenReturn(...)配置Mock的查询行为,让findById返回存在的实体,避免校验失败
场景2:集成测试(真实数据库)
如果要测试完整流程(包括Repository的真实查询和保存逻辑),不需要Mock Repository,而是用内存数据库(比如H2)提前插入真实的乘客和行程实体。
修改后的测试代码示例:
import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import java.util.UUID; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.verify; @SpringBootTest public class RegistrationServiceIntegrationTest { @Autowired private PassengerRepository passengerRepository; @Autowired private TripRepository tripRepository; @Autowired private RegistrationRepository registrationRepository; @Autowired private RegistrationService registrationService; @Test public void whenRegisterPassengerToTrip_thenReturnPassInTrip(){ // prepare UUID passengerId = UUID.randomUUID(); UUID tripId = UUID.randomUUID(); Integer seatNumber = 5; // 提前插入乘客和行程到数据库 Passenger passenger = new Passenger(); passenger.setId(passengerId); passengerRepository.save(passenger); Trip trip = new Trip(); trip.setId(tripId); tripRepository.save(trip); // testing PassInTrip passInTrip = registrationService.registerPassengerToTrip(passengerId, tripId, seatNumber); // validate verify(registrationRepository).save(any()); assert registrationRepository.findById(passInTrip.getId()).isPresent(); } }
关键操作:
- 用
@SpringBootTest启动Spring上下文,注入真实的Repository和Service实例 - 测试前通过Repository的
save方法把乘客和行程存入内存数据库,确保服务能查询到对应实体
总结
- 单元测试:必须Mock PassengerRepository和TripRepository,模拟实体存在的情况,专注测试Service的业务逻辑
- 集成测试:不需要Mock,用真实数据库提前插入实体,验证完整的业务流程
内容的提问来源于stack exchange,提问作者DOKL57
相关产品推荐
相关产品推荐

