Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to mock jdbc connection and resultSet using Mockito in TestNG

I have to write some unit tests but I have problem with mocking ResultSet and jdbc Connection.

I have this method:

@Test
public void test3() throws SQLException, IOException {

    Connection jdbcConnection = Mockito.mock(Connection.class);
    ResultSet resultSet = Mockito.mock(ResultSet.class);

    Mockito.when(resultSet.next()).thenReturn(true).thenReturn(true).thenReturn(true).thenReturn(false);
    Mockito.when(resultSet.getString(1)).thenReturn("table_r3").thenReturn("table_r1").thenReturn("table_r2");
    Mockito.when(jdbcConnection
            .createStatement()
            .executeQuery("SELECT name FROM tables"))
            .thenReturn(resultSet);

    //when
    List<String> nameOfTablesList = null;
    try {
        nameOfTablesList = Helper.getTablesName(jdbcConnection);
    } catch (SQLException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

    //then
    Assert.assertEquals(nameOfTablesList.size(), 3);
}

And error is showing in line executeQuery("SELECT name FROM tables") and it sounds like this:

java.lang.NullPointerException HelperTest.test3(HelperTest.java:71)

Any ideas whats going wrong?

like image 280
kosmit Avatar asked Jan 21 '16 09:01

kosmit


People also ask

Can we use Mockito in TestNG?

Mockito is a mocking framework. It is a Java-based library used to create simple and basic test APIs for performing unit testing of Java applications. It can also be used with other frameworks such as JUnit and TestNG.

How do you mock in Dbconnection?

You should adhere to Interface Segregation and Dependency Inversion principle by using Inversion of Control with the help of Dependency Injection. This way, you can create a MockDB2Connection, which you inject into the constructor, in your unit tests, while in your real code, you pass a proper DB2Connection.

Can we mock interface using Mockito?

The Mockito. mock() method allows us to create a mock object of a class or an interface. We can then use the mock to stub return values for its methods and verify if they were called.


2 Answers

You need to create an expectation on jdbcConnection.createStatement().

By default, I believe a null is returned.

Should read something like:

ResultSet resultSet = Mockito.mock(ResultSet.class);
Mockito.when(resultSet.next()).thenReturn(true).thenReturn(true).thenReturn(true).thenReturn(false);
Mockito.when(resultSet.getString(1)).thenReturn("table_r3").thenReturn("table_r1").thenReturn("table_r2");

Statement statement = Mockito.mock(Statement.class);
Mockito.when(statement.executeQuery("SELECT name FROM tables")).thenReturn(resultSet);

Connection jdbcConnection = Mockito.mock(Connection.class);
Mockito.when(jdbcConnection.createStatement()).thenReturn(statement);
like image 111
Nick Holt Avatar answered Oct 12 '22 10:10

Nick Holt


Mocking the JDBC API on this low level is rather tedious as you should really look into mocking the entirety of the JDBC API. Just a few examples:

  • What would happen if anyone called ResultSet.previous()?
  • What would happen if anyone called ResultSet.getObject() rather than getString()?
  • What would happen if the ResultSet was obtained through Statement.getResultSet()?

To your client code, it shouldn't matter much if you're calling JDBC one way or another, the result should always be the same. If you really have to mock the database (rather than use e.g. a test database, or better, a testcontainers based approach), then using something like jOOQ's MockDataProvider or MockFileDatabase would certainly make things much simpler. In your case:

MockDataProvider db = new MockFileDatabase(
    "SELECT name FROM tables;\n"
  + "> name\n"
  + "> --------\n"
  + "> table_r3\n"
  + "> table_r1\n"
  + "> table_r2\n"
  + "> @rows: 3\n");

//when
List<String> nameOfTablesList = null;
try {
    nameOfTablesList = Helper.getTablesName(new MockConnection(db));
} catch (SQLException e) {
    e.printStackTrace();
}

//then
Assert.assertEquals(nameOfTablesList.size(), 3);

The above approach will work regardless what the Helper.getTablesName() method does with the passed JDBC Connection.

Note, I'm working for the company behind jOOQ, so this answer is biased.

like image 39
Lukas Eder Avatar answered Oct 12 '22 08:10

Lukas Eder