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

使用Mockito @Spy注解时无法初始化@Mock字段的问题

问题原因

问题出在字段初始化顺序:Java会先执行类中字段的赋值语句(也就是new QuestionInfoService(repository)),之后Mockito才会处理@Mock注解创建真正的Mock实例。因此当你创建Spy对象时,repository还只是null,导致Spy内部的成员变量也变成了null。

正确解决方案

方案1:使用@InjectMocks自动注入

用@InjectMocks让Mockito自动将已初始化的Mock实例注入到Spy对象中,无需手动new:

@RunWith(MockitoJUnitRunner.class)
public class QuestionInfoServiceTest {

    @Mock
    QuestionInfoRepository repository;

    @Spy
    @InjectMocks
    QuestionInfoService questionInfoService;

    @Test
    public void shouldFetchQuestions() {
        System.out.println(questionInfoService.getRepository()); // 输出Mock实例
    }
}

Mockito会通过构造函数注入(因QuestionInfoService使用了@AllArgsConstructor),自动把repository Mock注入到Spy里。

方案2:在@Before方法中手动创建Spy

利用@Before方法的执行时机(所有测试方法前执行,此时@Mock已完成初始化),手动创建Spy:

@RunWith(MockitoJUnitRunner.class)
public class QuestionInfoServiceTest {

    @Mock
    QuestionInfoRepository repository;

    QuestionInfoService questionInfoService;

    @Before
    public void setup() {
        questionInfoService = Mockito.spy(new QuestionInfoService(repository));
    }

    @Test
    public void shouldFetchQuestions() {
        System.out.println(questionInfoService.getRepository()); // 输出Mock实例
    }
}

这种方式更灵活,适合需要自定义Spy创建逻辑的场景。

方案3:JUnit 5兼容写法(MockitoExtension)

如果使用JUnit 5,可通过MockitoExtension配合@BeforeEach确保Mock先初始化再创建Spy:

@ExtendWith(MockitoExtension.class)
public class QuestionInfoServiceTest {

    @Mock
    QuestionInfoRepository repository;

    QuestionInfoService questionInfoService;

    @BeforeEach
    public void setup() {
        questionInfoService = Mockito.spy(new QuestionInfoService(repository));
    }

    @Test
    public void shouldFetchQuestions() {
        System.out.println(questionInfoService.getRepository());
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 06:43:35