You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用@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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 12:46:18