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

SpringBoot中如何为依赖其他服务的BookManagementService编写测试并解决空指针异常

解决BookManagementService测试中的依赖模拟与空指针问题

我看你这测试里的问题主要是依赖注入的方式没搞对,导致YearService一直是null,才抛出空指针异常。咱们一步步来修正:

核心问题分析

你在setUp里手动new了BookManagementService和各个服务,但这个手动创建的实例里,authorService、genreService还有最初传入的yearService都是未初始化的状态——毕竟你是先创建了service,后面才给yearService赋值的,而且另外两个服务根本没赋值到service里,自然会空指针。另外,@SpringBootTest和MockitoExtension一起用容易冲突,纯单元测试没必要加载完整Spring上下文。

修正后的测试代码

@ExtendWith(MockitoExtension.class)
class BookManagementServiceTest {
    // 要测试的目标服务,Mockito会自动注入依赖
    @InjectMocks
    private BookManagementService bookManagementService;

    // 模拟BookManagementService中构造注入的Repo
    @Mock
    private BookRepo bookRepo;
    @Mock
    private BookItemRepo bookItemRepo;
    @Mock
    private BookEditionRepo bookEditionRepo;

    // 模拟BookManagementService中@Autowired注入的三个服务
    @Mock
    private AuthorService authorService;
    @Mock
    private YearService yearService;
    @Mock
    private GenreService genreService;

    // 模拟三个服务依赖的Repo(如果需要配置这些Repo的行为的话)
    @Mock
    private BookYearRepo bookYearRepo;
    @Mock
    private GenreRepo genreRepo;
    @Mock
    private AuthorRepo authorRepo;

    @BeforeEach
    void setUp() {
        // 这里不需要手动new任何实例!Mockito会通过@InjectMocks自动创建并注入依赖

        // 先配置底层Repo的行为(如果YearService的方法依赖bookYearRepo的话)
        lenient().when(bookYearRepo.findByYear("2006")).thenReturn(year);
        lenient().when(bookYearRepo.save(year)).thenReturn(year);

        // 配置各个服务的行为,比如YearService的create方法
        lenient().when(yearService.create("2006", edition)).thenReturn(year);

        // 配置BookManagementService依赖的Repo行为
        lenient().when(bookItemRepo.save(item)).thenReturn(item);
        lenient().when(bookEditionRepo.save(edition)).thenReturn(edition);
        lenient().when(bookRepo.save(book)).thenReturn(book);
    }

    // 你的测试方法写在这里
    @Test
    void testSomeBusinessMethod() {
        // 调用bookManagementService的方法进行测试
    }
}

关键修正点

  • 去掉@SpringBootTest:纯单元测试用@ExtendWith(MockitoExtension.class)足够,不用加载Spring上下文,测试速度更快。
  • 正确使用@InjectMocks:只需要给目标服务BookManagementService加这个注解,Mockito会自动创建它的实例,同时把所有标注了@Mock的依赖(不管是构造注入的Repo还是字段注入的服务)自动注入进去,完全不需要手动new。
  • 模拟所有依赖:把AuthorService、YearService、GenreService都声明为@Mock,这样它们就不会是null,你可以通过when().thenReturn()来配置它们的方法返回值,避免空指针。
  • 调整配置顺序:先配置底层Repo的行为,再配置依赖这些Repo的服务的行为,逻辑更清晰。

额外提示

如果你需要测试YearService本身的逻辑,那可以单独写一个YearServiceTest,在里面模拟BookYearRepo,不用在BookManagementServiceTest里关心YearService内部的Repo细节——毕竟咱们测试的是BookManagementService,只需要确保调用yearService.create()时能得到预期的返回值就行。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.28 16:12:36