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?
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.
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.
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.
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);
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:
ResultSet.previous()
?ResultSet.getObject()
rather than getString()
?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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With