使用Mockito测试DishService时出现NullPointerException该如何解决?
问题原因
- 你当前的单元测试使用
@ExtendWith(MockitoExtension.class)属于纯Mockito单元测试,不会启动Spring上下文,因此测试类上的@Autowired注解完全不生效。@InjectMocks只会将你声明了@Mock注解的依赖注入到DishService实例中。 - 你没有将Clock声明为测试依赖,
@InjectMocks创建DishService实例时,会给构造方法的Clock参数传入null。你在测试方法内部定义的clock是局部变量,根本不会赋值给DishService的成员变量,因此调用getAllToday时就会抛出clock空指针异常。 - 直接启动应用正常是因为Spring会加载TimeConfig里的Clock Bean,自动注入到DishService的构造方法中。
解决方案
方案1:保持纯Mockito单元测试(推荐,执行速度快)
补充Clock实例供@InjectMocks注入,删除无效的@Autowired注解即可:
@ExtendWith(MockitoExtension.class) class DishServiceTest { @Mock DishRepository dishRepository; @Mock RestaurantRepository restaurantRepository; // 补充Clock实例,可直接用真实实现也可以Mock Clock clock = Clock.systemDefaultZone(); @InjectMocks DishService dishService; @Test void shouldReturnAllDishesToday_whenGetAllToday() { // 提前抽取日期变量,避免两次调用now产生的时间差导致Stub不匹配 LocalDate today = LocalDate.now(clock); Mockito.when(dishRepository.getAllByDateAdded(today)).thenReturn(getDishes()); List<DishResponseDTO> resultList = dishService.getAllToday(); assertEquals(4, resultList.size()); assertEquals(getResponseDishes().get(3), resultList.get(3)); } }
方案2:使用SpringBoot测试加载上下文
如果需要复用Spring的配置(比如加载TimeConfig的Clock Bean),可以改成Spring Boot测试模式:
@SpringBootTest class DishServiceTest { @MockBean DishRepository dishRepository; @MockBean RestaurantRepository restaurantRepository; @Autowired DishService dishService; @Autowired Clock clock; @Test void shouldReturnAllDishesToday_whenGetAllToday() { LocalDate today = LocalDate.now(clock); Mockito.when(dishRepository.getAllByDateAdded(today)).thenReturn(getDishes()); List<DishResponseDTO> resultList = dishService.getAllToday(); assertEquals(4, resultList.size()); assertEquals(getResponseDishes().get(3), resultList.get(3)); } }
内容的提问来源于stack exchange,提问作者user15599360
相关产品推荐
相关产品推荐

