使用@Inject的Service测试中@InjectMocks注入失效问题
问题
我正在测试一个通过@Inject注解注入依赖的Service,但在测试过程中无法使用@InjectMocks正确注入其他依赖。示例Service代码如下:
@Component public class UpdateFileService { @Inject FolderRepository folderRepository; @Inject PermissionDTOConverter permissionConverter; }
其中PermissionDTOConverter是我不需要Stub的类。我期望测试代码按如下方式运行:
public class UpdateFileSecurityServiceTest { @Mock private FolderRepository folderRepository; @InjectMocks private PermissionDTOConverter permissionDTOConverter; @InjectMocks private UpdateFileSecurityService service; }
但调用测试方法时会抛出NullPointerException,提示DTO不存在。不过改用构造注入的方式后,测试即可正常运行:
public class UpdateFileSecurityServiceTest { @Mock private FolderRepository folderRepository; @InjectMocks private PermissionDTOConverter permissionDTOConverter; @InjectMocks private UpdateFileSecurityService service; @Before public void setUp() { service = new UpdateFileSecurityService(folderRepository, permissionDTOConverter); } }
请问为何@InjectMocks无法正常完成注入,如何正确配置以避免手动使用构造注入?
原因与解决方案
核心原因
@InjectMocks的作用是把已创建的Mock/Spy对象注入到被测试的目标类实例中,它不会自动实例化非Mock/Spy的普通类。你给PermissionDTOConverter加@InjectMocks完全无效,Mockito不会为它创建实例,导致这个对象一直是null,最终注入到UpdateFileService时触发空指针。- 原始测试中,
UpdateFileService的permissionConverter字段无法被正确填充,因为依赖的PermissionDTOConverter本身就是null,@InjectMocks只会处理目标类的注入逻辑,但没法凭空造出一个真实的PermissionDTOConverter实例。
正确配置方式
方式1:手动实例化真实的PermissionDTOConverter
不需要给它加任何Mockito注解,直接new出真实对象,@InjectMocks会自动把Mock的folderRepository和手动创建的PermissionDTOConverter注入到UpdateFileService中:
public class UpdateFileSecurityServiceTest { @Mock private FolderRepository folderRepository; // 直接创建真实实例 private PermissionDTOConverter permissionDTOConverter = new PermissionDTOConverter(); @InjectMocks private UpdateFileSecurityService service; // 必须初始化Mockito注解 @Before public void setUp() { MockitoAnnotations.openMocks(this); } }
方式2:用@Spy处理真实类(需部分Stub时用)
如果PermissionDTOConverter需要保留真实逻辑,但偶尔需要Stub部分方法,可以用@Spy注解,Mockito会创建它的真实实例:
public class UpdateFileSecurityServiceTest { @Mock private FolderRepository folderRepository; @Spy private PermissionDTOConverter permissionDTOConverter = new PermissionDTOConverter(); @InjectMocks private UpdateFileSecurityService service; @Before public void setUp() { MockitoAnnotations.openMocks(this); } }
方式3:改造Service为构造注入(推荐)
虽然你想避免手动构造注入,但构造注入是Spring官方推荐的依赖注入方式,不仅更符合OOP原则,Mockito对构造注入的支持也更稳定可靠:
// 改造后的Service @Component public class UpdateFileService { private final FolderRepository folderRepository; private final PermissionDTOConverter permissionConverter; // Spring 4.3+可以省略@Autowired/@Inject注解 public UpdateFileService(FolderRepository folderRepository, PermissionDTOConverter permissionConverter) { this.folderRepository = folderRepository; this.permissionConverter = permissionConverter; } }
测试代码无需手动new对象,@InjectMocks会自动匹配构造方法参数完成注入:
public class UpdateFileSecurityServiceTest { @Mock private FolderRepository folderRepository; private PermissionDTOConverter permissionDTOConverter = new PermissionDTOConverter(); @InjectMocks private UpdateFileSecurityService service; @Before public void setUp() { MockitoAnnotations.openMocks(this); } }
内容的提问来源于stack exchange,提问作者rafaelpadu
相关产品推荐
相关产品推荐

