web-dev-qa-db-ja.com

TestNGでMockitoを使用してJDBC接続と結果セットをモックする方法

いくつかの単体テストを作成する必要がありますが、ResultSetとjdbc Connectionのモックに問題があります。

私はこの方法を持っています:

_@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);
}
_

そして、エラーはexecuteQuery("SELECT name FROM tables")行に表示されており、次のように聞こえます:

_Java.lang.NullPointerException HelperTest.test3(HelperTest.Java:71)
_

どんなアイデアが間違っているのですか?

11
kosmit

jdbcConnection.createStatement()expectationを作成する必要があります。

デフォルトでは、nullが返されると思います。

次のようなものを読む必要があります:

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);
20
Nick Holt

この低レベルでのJDBC APIのモックは、JDBC API全体のモックを実際に検討する必要があるため、かなり面倒です。ほんのいくつかの例:

  • 誰かがResultSet.previous()を呼び出したらどうなりますか?
  • 誰かがResultSet.getObject()ではなくgetString()を呼び出すとどうなりますか?
  • ResultSetStatement.getResultSet()を通じて取得された場合はどうなりますか?

クライアントコードにとって、JDBCを何らかの方法で呼び出しているかどうかは重要ではありません。結果は常に同じです。あなたが本当にデータベースをモックする必要がある場合(たとえば、テストデータベースを使用するのではなく、より良い testcontainersベースのアプローチ )次に、jOOQの MockDataProvider または MockFileDatabase のようなものを使用すると、物事がはるかに簡単になります。あなたの場合:

_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);
_

上記のアプローチは、Helper.getTablesName()メソッドが渡されたJDBC Connectionで何をするかに関係なく機能します。

注、私はjOOQの背後にいる会社で働いているため、この答えは偏っています。

1
Lukas Eder