Mockito测试报错:无法实例化@InjectMocks标注的UserServiceImpl
报错信息
Cannot instantiate @InjectMocks field named 'userService' of type 'UserServiceImpl'. You haven't provided the instance at field declaration so I tried to construct the instance.
场景说明
UserServiceImpl继承AbstractPagingService<User, Integer, UserEntity>后触发上述报错,不继承该抽象类时测试正常。相关代码如下:
UserService接口
public interface UserService { Optional<User> getByToken(String token); PagingDto<User> getUsers(String filter, Integer startIndex, Integer count); }
UserServiceImpl实现类
public class UserServiceImpl extends AbstractPagingService<User, Integer, UserEntity> implements UserService { private final UserRepository userRepository; @Autowired public UserServiceImpl(ProviderConfiguration providerConfiguration, UserRepository userRepository) { super(providerConfiguration.getFilter().getMaxResult(), userRepository, Sort.by("surname")); this.userRepository = userRepository; } // 业务方法省略 }
测试类
@ExtendWith(SpringExtension.class) class UserServiceImplTest { private static final String TOKEN = "token"; @InjectMocks private UserServiceImpl userService; @Spy private UserRepository userRepository; // 测试方法省略 }
问题原因
Mockito的@InjectMocks自动实例化对象时,会优先调用类的构造方法。当前UserServiceImpl的构造方法需要两个参数:ProviderConfiguration和UserRepository,但测试类里只提供了UserRepository的Spy实例,缺了ProviderConfiguration的实例,导致Mockito无法完成构造。而继承抽象类后,Mockito的实例化逻辑会更严格,没有 fallback 路径,所以直接抛出报错。
解决方案
方案1:补充ProviderConfiguration的Mock实例
在测试类中添加ProviderConfiguration的Mock,并模拟其必要的返回值,让Mockito能调用构造方法完成实例化。
@ExtendWith(SpringExtension.class) class UserServiceImplTest { private static final String TOKEN = "token"; @InjectMocks private UserServiceImpl userService; @Spy private UserRepository userRepository; // 添加ProviderConfiguration的Mock @Mock private ProviderConfiguration providerConfiguration; @BeforeEach void setUp() { // 模拟providerConfiguration的getFilter().getMaxResult()返回值 FilterConfig filterConfig = mock(FilterConfig.class); when(filterConfig.getMaxResult()).thenReturn(10); // 根据业务需求设置数值 when(providerConfiguration.getFilter()).thenReturn(filterConfig); } // 原测试方法保留 }
方案2:手动实例化UserServiceImpl
直接在初始化方法里手动创建服务类实例,传入所需的Mock对象,完全控制实例化过程,绕开@InjectMocks的自动构造逻辑。
@ExtendWith(SpringExtension.class) class UserServiceImplTest { private static final String TOKEN = "token"; private UserServiceImpl userService; @Spy private UserRepository userRepository; @Mock private ProviderConfiguration providerConfiguration; @BeforeEach void setUp() { // 模拟必要的依赖返回值 FilterConfig filterConfig = mock(FilterConfig.class); when(filterConfig.getMaxResult()).thenReturn(10); when(providerConfiguration.getFilter()).thenReturn(filterConfig); // 手动实例化服务类 userService = new UserServiceImpl(providerConfiguration, userRepository); } // 原测试方法保留 }
总结
本质是构造方法的依赖参数未在测试中齐全,继承抽象类后Mockito的实例化逻辑不再有 fallback,必须满足构造方法的参数要求。补充缺失的Mock或者手动实例化服务类,就能解决这个问题。
内容的提问来源于stack exchange,提问作者Jack

