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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 21:57:35