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

@InjectMocks仅注入类的全局变量吗?为何Mock对象未成功注入到SomeClass中?

解答你的两个Mockito疑问

嘿,我来帮你把这两个问题捋清楚,咱们一个个来:

一、@InjectMocks仅会注入类的全局变量吗?

没错,@InjectMocks只能作用于类的成员变量(也就是你说的全局变量),不管这个变量是private、protected还是默认访问权限,它都能通过反射机制尝试注入。它的注入优先级大概是:

  • 优先使用构造方法注入:如果被测试类有带依赖参数的构造方法,Mockito会把对应的Mock对象传入构造方法创建实例
  • 其次是Setter方法注入:如果有对应依赖的Setter方法(比如setSomeDao(SomeDao dao)),会调用Setter注入Mock
  • 最后是直接字段注入:如果前面两种都不满足,会直接通过反射替换类的成员变量值

但要注意,它完全管不到方法内部的局部变量——比如你第一种写法里someMethod()里new的SomeDao,@InjectMocks根本看不到这个变量,自然没法替换。

二、为什么你的Mock对象无法生效?

咱们针对你写的两种SomeClass写法分别分析:

1. 方法内部直接实例化依赖的情况

public class SomeClass {
    private void someMethod() {
        SomeDao someDao = new SomeDao(); // 这里是方法局部变量
        someDao.retrieveSomeData();
    }
}

这里的someDao是someMethod()里的局部变量,完全是方法执行时才创建的新对象,和你测试类里用@Mock创建的someDao没有任何关系。Mockito没有能力干涉方法内部自己new出来的对象,所以调用的必然是真实方法。

2. 构造方法内实例化依赖的情况

public class SomeClass{
    SomeDao someDao;
    public SomeClass() {
        someDao = new SomeDao(); // 构造方法里直接new真实实例
    }
    private void someMethod() {
        someDao.retrieveSomeData();
    }
}

这里的问题有两个:

  • 你在测试类里手动new了SomeClass实例:private SomeClass someClass = new SomeClass();。当你手动调用无参构造方法时,已经把真实的SomeDao赋值给了成员变量。虽然@InjectMocks会尝试通过反射替换这个成员变量,但这种写法很容易出问题(比如反射替换时机晚于构造方法执行)。
  • 更核心的是,SomeClass自己在构造方法里硬编码创建了依赖,没有给外部替换依赖的入口——这违背了依赖注入原则,导致Mockito没法把Mock对象真正塞进去。

解决方案:修改依赖注入方式

要让Mock生效,你得让SomeClass的依赖可以从外部传入,而不是自己内部new。最推荐的是构造方法注入(因为它能保证依赖不可变,且实例创建时依赖就准备好):

修改SomeClass:

public class SomeClass{
    private final SomeDao someDao;

    // 用带参数的构造方法接收外部传入的依赖
    public SomeClass(SomeDao someDao) {
        this.someDao = someDao;
    }

    // 把方法改成public,不然测试里没法调用它
    public void someMethod() {
        someDao.retrieveSomeData();
    }
}

修改测试类:

@ExtendWith(MockitoExtension.class)
public class SomeClassTest {
    @Mock
    private SomeDao someDao;

    // 不要手动new,让Mockito通过构造方法注入Mock对象
    @InjectMocks
    private SomeClass someClass;

    @Test
    void test() {
        // 定义Mock的返回逻辑
        when(someDao.retrieveSomeData()).thenReturn(10);

        // 调用被测试方法
        someClass.someMethod();

        // 验证Mock方法是否被正确调用(这一步很重要,确保Mock生效了)
        verify(someDao).retrieveSomeData();
    }
}

这样修改后,Mockito会用你创建的Mock版SomeDao作为参数,调用SomeClass的构造方法创建实例,此时someClass里的someDao就是你定义的Mock对象,调用retrieveSomeData()时就会执行你设置的返回逻辑,而不是真实方法。


内容的提问来源于stack exchange,提问作者Wumba

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 13:22:31