Mockito测试中CartService的@Autowired UserService为null,能否正常测试?
问题原因
你遇到的空指针异常,核心原因是CartService上的@RequiredArgsConstructor注解会生成一个仅包含final修饰字段的构造函数,而@Autowired标注的userService并没有被声明为final,所以不会出现在这个构造函数里。
Mockito的@InjectMocks默认优先使用构造函数注入,因此只会给构造函数里的cartRepository、productRepository、cartItemRepository赋值,完全忽略了userService字段,导致调用时出现null。
解决方案(保留@Autowired注入方式)
方案1:用反射工具手动注入(最通用)
借助Spring的ReflectionTestUtils,在测试初始化阶段把mock的userService手动设置到cartService的私有字段中,不需要修改业务类代码:
@ExtendWith(MockitoExtension.class) class CartServiceTest { @Mock private CartRepository cartRepository; @Mock private CartItemRepository cartItemRepository; @Mock private UserRepository userRepository; @Mock private ProductRepository productRepository; @Mock private UserService userService; @InjectMocks private CartService cartService; @BeforeEach void setUp() { // 手动注入userService字段 ReflectionTestUtils.setField(cartService, "userService", userService); } @Test void checkedClearCartFromAllItems(){ Principal principal = mock(Principal.class); User user = mock(User.class); when(userService.getUserOfPrincipal(principal)).thenReturn(user); cartService.clearCart(principal); } }
方案2:指定Mockito优先使用字段注入
如果不想用反射,可以调整Mockito的注入策略,让它优先通过字段注入而不是构造函数注入。需要手动初始化cartService并指定注入器:
@ExtendWith(MockitoExtension.class) class CartServiceTest { @Mock private CartRepository cartRepository; @Mock private CartItemRepository cartItemRepository; @Mock private UserRepository userRepository; @Mock private ProductRepository productRepository; @Mock private UserService userService; private CartService cartService; @BeforeEach void setUp() { // 先通过构造函数初始化cartService cartService = new CartService(cartRepository, productRepository, cartItemRepository); // 开启Mock并指定用字段注入策略 MockitoAnnotations.openMocks(this, MockitoInjector.STRICT_STUBS); } @Test void checkedClearCartFromAllItems(){ Principal principal = mock(Principal.class); User user = mock(User.class); when(userService.getUserOfPrincipal(principal)).thenReturn(user); cartService.clearCart(principal); } }
注:虽然Spring官方更推荐
@RequiredArgsConstructor+构造函数注入的方式(更利于测试和依赖透明性),但以上两种方案都能满足你保留@Autowired注入userService的需求。
内容的提问来源于stack exchange,提问作者Alexis
相关产品推荐
相关产品推荐

