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
相关产品推荐
相关产品推荐

