2

I am working on a tiny framework to wrap Database Stored Procedure calls named spwrap

Here's the code:

@ConfineMetaClassChanges([CallableStatement])
def "Result of output parameter getInt throws SQLException" (){

    given:
        def sqlExceptionMsg = "exception happend while tring to call getInt"
        CallableStatement.metaClass.getObject = { int parameterIndex -> throw new SQLException(sqlExceptionMsg)}

    when:
        def custId = customerDao.createCustomer("Abdullah", "Mohammad")

    then:
        def e = thrown(CallException)
        e.cause == SQLException
        e.cause.message == sqlExceptionMsg
}

the method createCustomer returns no reference to CallableStatement, however under the hood a CallableStatement.getObject(int) is being called, and I want to test the case where a SQLException is thrown.

I am trying to override the bahvaiour on the CallableStatement.getObject(int) class (since I have to reference to the used object by the framework - at least in this scenario)

The above test fails as it seems the CallableStatement.getObject(int) is not being changed. However when i use the << it complains (and it should). How to accomplish this?

UPDATE:

Using GroovyMock doesn't help:

// test fails!
def "Calling interface methods calling JDBC Driver methods" (){
    given:
        CustomerDAO customerDAO2 = new DAO.Builder("jdbc:hsqldb:mem:customers", "sa", "").build().create(CustomerDAO);
        def callableStatement = GroovyMock(JDBCCallableStatement, global: true)
    when:
        customerDAO2.createCustomer("Abdullah", "Mohammad")
    then:
        1 * callableStatement.getObject(_ as Integer)
}

Can I achieve this with other Mocking frameworks?

Community
  • 1
  • 1
Muhammad Hewedy
  • 29,102
  • 44
  • 127
  • 219
  • Since I'm not entirely familiar with groovy metaclasses, I have a question: does altering metaclass of interface affects all implementations of that interface? Because if it's not (and I will expect it so, given Java proxying constraints), then code in this question does nothing to the actual jdbc driver implementation of `CallableStatement`. – M. Prokhorov Feb 21 '17 at 16:45
  • Is there any specific reason for you not to use normal mocks or stubs but to fiddle with meta classes? – kriegaex Feb 21 '17 at 23:54
  • No, but i think mocks works with particular instance of the class, but this is not my case. – Muhammad Hewedy Feb 22 '17 at 05:04

1 Answers1

1

In my experience Spock isn't very powerful when it comes to Mocking static/final Java code. One of the workarounds I've taken to doing is placing any such method calls in their own method, which Spock should have no problem hooking into.

public class MyClass {
    //... stuff ...

    protected Object retrieveObject(int) throws SQLException {
        return CallableStatement.getObject(int)
    }
}

public class MyClassTest extends Specification {
def "Test example for wrapping unmockable method" (){
    given:
        MyClass example = new MyClass();
    when:
        example.callMethod("Parameters")
    then:
        1 * example.retrieveObject(_) >> { throw new SQLException(sqlExceptionMsg) }
}
}
ScientificMethod
  • 493
  • 3
  • 10