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

添加Connection等参数后JUnit测试报错:Cannot open transaction cause it is null

Let's break down what's causing your error and fix it step by step:

Root Cause of the Error

When your test triggers the SQLException in getTotalRecords, the code enters the catch block and calls SEEntityManager.rollbackAndReOpenTransaction(). This static method is trying to access a transaction object that hasn't been initialized in your test environment, hence the "Cannot open transaction cause it is null" error. Additionally, several of your mock objects aren't properly configured to handle the secondary calls in the catch block.

Step 1: Mock the Static SEEntityManager Method

Since rollbackAndReOpenTransaction() is a static method, you'll need to mock it using Mockito's static mocking support (available in Mockito 3.4+). This prevents the method from trying to access a real, uninitialized transaction.

Step 2: Fix Mock Configurations for Dependencies

You need to properly configure all mock objects to handle every call made in the business logic, including those in the catch block:

  • Mock the Connection to return a new Statement when createStatement() is called
  • Mock NotificationData to return a valid SQL string for getFieldSql()
  • Configure the initial Statement to throw an SQLException on its first executeQuery() call

Revised Test Code

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.MockedStatic;
import org.mockito.junit.jupiter.MockitoExtension;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.Mockito.*;

@ExtendWith(MockitoExtension.class)
public class DAODefaultTest {

    @Test
    public void verifyExceptionCountRecords() throws SQLException {
        // 1. Create all required mock objects
        Connection mockConn = mock(Connection.class);
        Statement initialMockStmt = mock(Statement.class);
        Statement newMockStmt = mock(Statement.class);
        ResultSet mockRs = mock(ResultSet.class);
        NotificationData mockNotification = mock(NotificationData.class);

        // 2. Configure mock behaviors
        // Make the initial statement throw SQLException on executeQuery
        when(initialMockStmt.executeQuery(anyString())).thenThrow(new SQLException());

        // Mock the static SEEntityManager method to avoid transaction errors
        try (MockedStatic<SEEntityManager> mockedSEEntityManager = mockStatic(SEEntityManager.class)) {
            mockedSEEntityManager.when(SEEntityManager::rollbackAndReOpenTransaction).thenReturn(null);

            // Make connection return a new mock statement
            when(mockConn.createStatement()).thenReturn(newMockStmt);
            // Make notification return a valid SQL string
            when(mockNotification.getFieldSql()).thenReturn("SELECT 1 FROM dummy");
            // Configure the new statement's executeQuery (optional, since we return BROKE_SQL)
            when(newMockStmt.executeQuery(anyString())).thenReturn(mockRs);

            // 3. Execute the test
            int result = daoDefault.getTotalRecords(mockConn, initialMockStmt, "", mockNotification);
            // Note: Your business code returns BROKE_SQL, not 0 - adjust assertion accordingly
            assertTrue(result == DAODefault.BROKE_SQL);

            // 4. Verify expected behaviors
            verify(mockRs, never()).getInt("ROWS_COUNT");
            mockedSEEntityManager.verify(SEEntityManager::rollbackAndReOpenTransaction, times(1));
        }
    }
}

Bonus: Fix Resource Leak in Business Code

Your catch block uses a raw Statement and ResultSet without proper resource management. Update it to use try-with-resources to avoid leaks:

catch (SQLException e) {
    try{
        SEEntityManager.rollbackAndReOpenTransaction();
        try(Statement newStmt = connection.createStatement();
            ResultSet newRs = newStmt.executeQuery(notification.getFieldSql())) {
            return BROKE_SQL;
        }
    }catch (final SQLException e1){
        logger.error(e1.getMessage(), e1);
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 16:50:16