模拟Oracle可调用语句.getCursor()



我正在处理一个Oracle 10g数据库,并提供了以下存储过程:

 procedure get_synopsis (
   p_id in  my_schema.products.p_id%type,
   p_synopses out sys_refcursor);  -- cursor of - synopsis_type, synopsis_text

在我的Java代码中,我以这种方式准备语句:

String idForDb = fromIdUrlToIdDb(prodIdUrl); 
statement.registerOutParameter(1, OracleTypes.VARCHAR);
statement.setString(1, idForDb );
statement.registerOutParameter(2, OracleTypes.CURSOR);

我通过这种方式获得我需要的数据:

String defaultSyn, nonDefSyn;
String returnedId = ((OracleCallableStatement)stm).getString(1);
try ( ResultSet synopses = ((OracleCallableStatement)stm).getCursor(2) ){ // p_synopses - cursor of: synopsis_type, synopsis_text
    while( synopses!=null && synopses.next() ){
        String type = synopses.getString(1) != null ? synopses.getString(1).toUpperCase() : null;
        if( type != null ){
            StringBuilder sb = new StringBuilder();
            BufferedReader br = new BufferedReader( synopses.getClob(2).getCharacterStream() );
            String line;
            while ((line = br.readLine()) != null) {
               sb.append(line).append("n");
            }
            if("DEFAULT".equals(type)){
                defaultSyn = sb.toString();
            }else if("NONDEFAULT".equals(type)){
                nonDefSyn = sb.toString();
            }
            // ...
        }
    }
}

在我的测试中,如何模拟(OracleCallableStatement)stm.getCursor(2)

我正在尝试org.jmockery,但没有成功:

Mockery mockery_inner = new Mockery();
final ResultSet mocked_resultset = mockery_inner.mock(ResultSet.class);
mockery_inner.checking(new Expectations() {{
    allowing(mocked_resultset).getString(1); will(returnValue("TEST_SYNOPSES-TYPE"));
    allowing(mocked_resultset).getClob(2); will(returnValue("TEST_CLOooooooB"));
}});
Mockery mockery = new Mockery();
final CallableStatement statement = mockery.mock(CallableStatement.class);
mockery.checking(new Expectations() {{
    allowing(statement).getString(1); will(returnValue("TEST_RETURNED-PROD-ID"));
    allowing(statement).getCursor(2); will(returnValue(mocked_resultset));  // cannot find symbol getCursor(int). Location: interface java.sql.CallableStatement
}});   

原因很明显是:找不到符号getCursor(int)。位置:接口java.sql.CallableStatement.

如果我尝试允许((OracleCallableStatement)语句).getCursor(2),我会得到"java.lang.ClassCastException.com.sun.proxy.$Proxy6不能强制转换为oracle.jdbc.driver.OracleCallableStatements"。注意:OracleCallableStatement不是一个接口,因此不能用Mockery进行模拟。

我正在尝试使用"手动"mock,但在创建实例时遇到了问题。。

class MockOracleCallableStatement implements OracleCallableStatement {
    ResultSet mocked_resultset;
    public MockOracleCallableStatement(){
        Mockery mockery_inner = new Mockery();
        mocked_resultset = mockery_inner.mock(ResultSet.class);
        mockery_inner.checking(new Expectations() {{
            allowing(mocked_resultset).getString(1); will(returnValue("DEFAULT")); // will pick value from an array
            allowing(mocked_resultset).getClob(2); will(returnValue("TEST_CLOooooooooooB"));
        }});
    }
    @Override
    ResultSet getCursor(int paramIndex) throws SQLException{
        return mocked_resultset;
    }
    @Override
    String getString(int paramIndex) throws SQLException{
        return "mockedGetString1--test";
    }
}

简而言之,不要

模拟JDBC(以及许多其他事情)是一件愚蠢的事情,它不会测试你认为它正在测试的东西,但会花费你大量的时间。

您真的应该编写一个集成测试,该测试实际应用于您的数据库。这是验证数据库代码是否正确的唯一方法。如果可以的话,使用与生产中完全相同的数据库版本,如果不使用像H2*这样的内存中数据库的话。

我为JAX杂志写了一篇关于这个主题的文章,这篇文章将更加详细。

  • 尽管由于兼容性的原因,这还有其他问题

我似乎可以使用Mockito。。

OracleCallableStatement oraCSMock = Mockito.mock(OracleCallableStatement.class);

更新:方法CLOB.getDBAccess(connection)是CLOB类的静态方法,因此不能用Mockito进行模拟。(您可以使用Powermock模拟静态)。

我最终只测试了404案例:

ResultSet mocked_resultset = Mockito.mock(ResultSet.class);
doReturn( null ) // cant' use "DEFAULT" since getClob() will throw npe anyway. Will test just 404 then.
.when(mocked_resultset).getString(1);
doReturn( false )
.when(mocked_resultset).next(); // or just return null in getCursor(2)

OracleCallableStatement statement = Mockito.mock(OracleCallableStatement.class);
doReturn( "testID" )
.when( statement ).getString(1);
doReturn( mocked_resultset )
.when( statement ).getCursor(2);

最新更新