无法模拟 connection.prepareCall 方法

问题描述

我无法模拟 connection.prepareCall("{call myStoreProcedure()}");调用 spring boot 项目。

每次我收到“org.h2.jdbc.JdbcsqlSyntaxErrorException:未找到列“myStoreProcedure”sql 语句:”,因为我使用的是 h2 数据库和我们没有那个程序。但是当我模拟它不应该调用数据库时它应该只返回模拟值......但它没有发生。

注意:我遇到了异常但我的测试用例正在通过。

下面是我的代码片段:

package com.khan;

import static org.mockito.Mockito.mock;

import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.ResultSet;

import javax.sql.DataSource;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.powermock.api.mockito.powermockito;
import org.powermock.core.classloader.annotations.PowerMockIgnore;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.powermockrunner;
import org.powermock.modules.junit4.powermockrunnerDelegate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBoottest;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(powermockrunner.class)
@powermockrunnerDelegate(SpringJUnit4ClassRunner.class)
@PrepareForTest({ DataSource.class,Connection.class,CallableStatement.class })
@SpringBoottest
@PowerMockIgnore({ "javax.management.*","javax.net.ssl.*","javax.security.auth.*" })
@TestPropertySource({ "classpath:application.properties" })
public class MainClasstest {

    @Autowired
    MainClass mainClass;

    @Autowired
    private DataSource dataSource;
    
    @Test
    public void testMethod() throws Exception {
        ResultSet resultSet = mock(ResultSet.class);
        CallableStatement callableStatement = mock(CallableStatement.class);
        Mockito.when(dataSource.getConnection()).thenReturn(connection);
        Mockito.when(connection.prepareCall("{  call myprocedure()}")).thenReturn(callableStatement);
        Mockito.when(callableStatement.executeQuery()).thenReturn(resultSet);
        
        //Tried below one as well but no luck
        //powermockito.stub(powermockito.method(Connection.class,"prepareCall",Mockito.any())).toReturn(callableStatement);
        
        mainClass.callProcedure("Procedure Name");
    }

}

下面是我的主类:

 public class MainClass{
    @Autowired
    private DataSource dataSource;
        
    public void callProcedure(String storedProcName) throws sqlException {
            Connection connection = dataSource.getConnection();
            try (CallableStatement cs = connection.prepareCall("{call " + storedProcName + "}");) { // I am getting exception here but test cases are passing
                cs.executeQuery();
            } catch (sqlException e) {
                log.error("Exception occured while execution of stored procedure having storedProcName: {} with reason: {} "
                        + e.getMessage(),storedProcName,e);
                throw e;
            }
    }
}

解决方法

我发现您的测试用例中有很多问题。

  1. 不需要加载 Spring Context 来测试这个类。 Mock 应该就够了。

  2. 在您的 callProcedure 中,您正在传递 "Procedure Name" 但在模拟中,您期望 "{ call myprocedure()}" 以便模拟永远不会被触发.

  3. 您的测试用例通过,因为您没有验证任何内容。

尝试如下操作。

@RunWith(PowerMockRunner.class)
public class MainClassTest {

    @InjectMocks
    MainClass mainClass;

    @Mock
    private DataSource dataSource;
    
    @Test
    public void testMethod() throws Exception {
        //Given
        ResultSet resultSet = mock(ResultSet.class);
        CallableStatement callableStatement = mock(CallableStatement.class);
        Mockito.when(dataSource.getConnection()).thenReturn(connection);
        Mockito.when(connection.prepareCall(anyString())).thenReturn(callableStatement);
        Mockito.when(callableStatement.executeQuery()).thenReturn(resultSet);
        
        //When
        mainClass.callProcedure("Procedure Name");

        //Then
        verify(dataSource,times(1)).getConnection();
    }
}