Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

problems mocking a class

Tags:

java

mockito

jdbi

I'm trying to mock the Query class of JDBI with mockito, however it fails to mock the methods of its base class SqlStatement.

When running the code below the when statement is actually calling the concrete implementation in the base class and fails with NullPointerException.

import java.util.Map;

import org.junit.Test;
import org.skife.jdbi.v2.Query;

import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

public class TestClass {
    @Test
    public void testBind() {
        Query<Map<String,Object>> mockQuery = mock(Query.class);
        when(mockQuery.bind("xxx", 5)).thenReturn(mockQuery); //this line fails
        //more stuff here
    }
}

I've tried this with EasyMock as well and got the same results, it fails to mock this method.

More Info:

  • Mockito version is 1.9.5
  • JDBI version is 2.4.1 (the one that currently ships with dropwizard)

The exception is:

    java.lang.NullPointerException
        at org.skife.jdbi.v2.SQLStatement.bind(SQLStatement.java:434)
        at TestClass.testBind(TestClass.java:17)
            at ....

Any ideas how to work around this?

like image 228
LiorH Avatar asked Oct 06 '22 09:10

LiorH


1 Answers

bind methods in SqlStatement are final (for exemple SQLStatement#bind(String, int)), so you cannot mock them using Mockito, it's a limitation of the JVM (EDIT:) that mockito cannot bypass at the moment.


EDIT2: Note that as the comments below point out, there is some misunderstanding of what's written above, and this requires clarification on my part:
  • The limitation of the JVM means you cannot load a subclass of a type that is flagged with a final access, you cannot override a method that is flagged with final access, otherwise you will get a VerifyError. §8.1.1.2 final classes of the Java Language Specification §8.4.3.3 final methods of the JLS §4.10 of the Java Virtual Machine Specification
  • that mockito cannot bypass means Mockito isn't currently able to overcome final classes or final methods in order to mock them, because at moment Mockito uses CGLIB to generate subclasses of the type to mock. But other frameworks (like PowerMock or JMockit) may be able to do it as they have other strategies to overcome this.

Your options are to change your design so you won't have to stub those interactions, or you have to use PowerMock which uses complicate tricks with classloaders to rewrite class bytecode (not my preferred approach, though PowerMock is technically impressive).

Hope that helps.

like image 66
Brice Avatar answered Oct 10 '22 02:10

Brice