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

使用MockitoAnnotations.openMocks()@BeforeClass初始化的字段在同类别测试中为null

问题根源与解决方案

核心问题分析

  1. JUnit 4生命周期误用:@BeforeClass注解的方法必须是静态方法,且只会在类加载时执行一次。你的代码中@BeforeClass修饰的是非静态方法,导致初始化操作仅在某个测试类实例上执行,但JUnit 4会为每个@Test方法创建新的测试类实例——测试方法中拿到的是未初始化的新storedProcedure对象,而非@BeforeClass中初始化的那个。
  2. Mockito新旧API差异:
    • MockitoAnnotations.initMocks(this):旧API,直接将mock注入目标字段,无资源自动清理机制,mock状态会持续到测试结束。
    • MockitoAnnotations.openMocks(this):新API,返回AutoCloseable实例,调用close()可重置mock并释放资源,需配合JUnit生命周期管理资源,否则易出现状态异常。

修复方案

方案一:使用实例级生命周期(推荐)

将类级别的@BeforeClass改为实例级的@Before,确保每个测试方法执行前都重新初始化mock和storedProcedure,避免测试间状态污染。

修改后的BaseMocks类

public abstract class BaseMocks {

    @Mock
    protected RowMapper<Object> mockRowMapper;

    @Mock
    protected Connection mockConnection;

    @Mock
    protected CallableStatement mockStatement;

    @Mock
    protected DataSourceProvider dsProvider;

    @Mock
    public DataSource mockDataSource;

    final MockResultSet mockResultSet = new MockResultSet("");

    private AutoCloseable closeable;

    @Before
    protected void openMocks() throws Exception {
        closeable = MockitoAnnotations.openMocks(this);
        Mockito.when(dsProvider.getDatasource(Mockito.anyString())).thenReturn(mockDataSource);
        Mockito.when(mockDataSource.getConnection()).thenReturn(mockConnection);
        Mockito.when(mockConnection.prepareCall(Mockito.anyString())).thenReturn(mockStatement);
        Mockito.when(mockStatement.getResultSet()).thenReturn(mockResultSet);
    }

    @After
    protected void closeMocks() throws Exception {
        if (closeable != null) {
            closeable.close();
        }
    }

    @BeforeMethod
    protected void resetMocks() throws SQLException {
        Mockito.reset(mockRowMapper);
        Mockito.when(mockStatement.getMoreResults()).thenReturn(true).thenReturn(false);
    }
}

修改后的AitGetMyDetailsTest类

public class AitGetMyDetailsTest extends BaseMocks {

    @InjectMocks
    private AitGetMyDetails storedProcedure;

    @Before
    public void setup() throws Exception {
        super.openMocks();
        storedProcedure.afterPropertiesSet();
    }

    @Test
    public void myTest() throws Exception {
        MyObj mockMyObj = Mockito.mock(MyObj.class);
        storedProcedure.execute(mockMyObj, 67,45);
    }
}

方案二:类级别初始化(不推荐,易导致测试间状态污染)

若必须使用类级别初始化,需将所有mock字段、storedProcedure改为静态,并将@BeforeClass方法改为静态。

修改后的BaseMocks类

public abstract class BaseMocks {

    @Mock
    protected static RowMapper<Object> mockRowMapper;

    @Mock
    protected static Connection mockConnection;

    @Mock
    protected static CallableStatement mockStatement;

    @Mock
    protected static DataSourceProvider dsProvider;

    @Mock
    public static DataSource mockDataSource;

    static final MockResultSet mockResultSet = new MockResultSet("");

    private static AutoCloseable closeable;

    @BeforeClass
    public static void openMocks() throws Exception {
        closeable = MockitoAnnotations.openMocks(BaseMocks.class);
        Mockito.when(dsProvider.getDatasource(Mockito.anyString())).thenReturn(mockDataSource);
        Mockito.when(mockDataSource.getConnection()).thenReturn(mockConnection);
        Mockito.when(mockConnection.prepareCall(Mockito.anyString())).thenReturn(mockStatement);
        Mockito.when(mockStatement.getResultSet()).thenReturn(mockResultSet);
    }

    @AfterClass
    public static void closeMocks() throws Exception {
        if (closeable != null) {
            closeable.close();
        }
    }

    @BeforeMethod
    protected void resetMocks() throws SQLException {
        Mockito.reset(mockRowMapper);
        Mockito.when(mockStatement.getMoreResults()).thenReturn(true).thenReturn(false);
    }
}

修改后的AitGetMyDetailsTest类

public class AitGetMyDetailsTest extends BaseMocks {

    @InjectMocks
    private static AitGetMyDetails storedProcedure;

    @BeforeClass
    public static void setup() throws Exception {
        openMocks();
        storedProcedure.afterPropertiesSet();
    }

    @Test
    public void myTest() throws Exception {
        MyObj mockMyObj = Mockito.mock(MyObj.class);
        storedProcedure.execute(mockMyObj, 67,45);
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 14:52:15