@Mock注解的作用是什么?能否与@BeforeClass配合使用?
@Mock注解的作用及与@BeforeClass的配合问题
一、@Mock注解的核心作用
- 自动生成Mock对象,替代手动编写
mock(目标类.class)的重复代码,让测试类更简洁 - 配合
@RunWith(MockitoJUnitRunner.class)(JUnit4)或@ExtendWith(MockitoExtension.class)(JUnit5)使用时,Mockito会自动完成Mock对象的初始化、后续交互验证与清理等工作,无需手动处理这些流程 - 搭配
@InjectMocks注解还能自动将Mock对象注入到被测类的依赖中,省去手动注入的代码
二、为什么你的代码会抛空指针?
问题出在Mockito的初始化时机和@BeforeClass的执行时机不匹配:
@RunWith(MockitoJUnitRunner.class)默认只会初始化非静态的@Mock成员变量,而且初始化动作是在每个测试方法执行前(也就是@Before方法执行前)完成的@BeforeClass是静态方法,会在整个测试类加载完成后、所有测试方法执行前就运行,此时静态的@Mock成员o还没被Mockito初始化,自然是null,调用o.toString()就会触发NPE
你提到的两种可行场景的原因也很明确:
- 改成非静态
@Before方法:此时Mockito已经完成了非静态@Mock成员的初始化,o是有效的Mock对象,所以能正常运行 - 手动用
= mock(Object.class)初始化静态变量:这是直接在类加载阶段就创建了Mock对象,和Mockito的注解初始化无关,所以@BeforeClass里能正常调用
三、让@Mock和@BeforeClass配合使用的方法
如果确实需要在@BeforeClass中使用@Mock标记的静态成员,有两种可行方案:
方案1:手动触发静态Mock的初始化
在@BeforeClass方法里手动调用Mockito的初始化方法,完成静态@Mock成员的初始化:
@RunWith(MockitoJUnitRunner.class) public class FooTest { @Mock private static Object o; private static AutoCloseable closeable; @BeforeClass public static void beforeClass() { // 手动初始化静态@Mock成员 closeable = MockitoAnnotations.openMocks(FooTest.class); when(o.toString()).thenReturn("foo"); } @AfterClass public static void afterClass() throws Exception { // 清理资源 closeable.close(); } @Test public void test() { assertEquals("foo", o.toString()); } }
注:
MockitoAnnotations.openMocks()是Mockito 3.5+版本的方法,旧版本可以用MockitoAnnotations.initMocks(),不过后者已被标记为过时。
方案2:Spring环境下用@MockBean
如果是在Spring Boot测试场景中,可以用@MockBean注解静态成员变量,Spring会在类加载阶段就完成Mock对象的初始化,这样@BeforeClass方法里就能直接使用该Mock对象。
最后说一句:@Mock绝不是多余的
你觉得它多余是因为只用到了它“替代手动mock”的基础功能,实际上它还有很多实用特性:
- 集中声明Mock对象,测试类结构更清晰,一眼就能区分哪些是Mock依赖
- 配合
@InjectMocks自动完成依赖注入,大幅简化被测类的初始化代码 - 支持Mockito的严格模式配置,自动检查无效的Mock交互,提前发现测试漏洞
内容的提问来源于stack exchange,提问作者H.v.M.
相关产品推荐
相关产品推荐

