web-dev-qa-db-fra.com

Comment se moquer de la connexion jdbc et de resultSet en utilisant Mockito dans TestNG

Je dois écrire quelques tests unitaires, mais je ne parviens pas à me moquer de ResultSet et de jdbc Connection

J'ai cette méthode:

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

Et l'erreur est indiquée sur la ligne executeQuery("SELECT name FROM tables") et sonne comme ceci: 

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

Des idées qui ne vont pas?

7
user3552976

Vous devez créer une expectation on jdbcConnection.createStatement().

Par défaut, je crois qu'une null est renvoyée.

Devrait lire quelque chose comme:

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

Il est assez fastidieux de se moquer de l'API JDBC à ce niveau bas, car vous devriez vraiment vous moquer de l'intégralité de l'API JDBC. Juste quelques exemples:

  • Que se passerait-il si quelqu'un appelait ResultSet.previous()?
  • Que se passerait-il si quelqu'un appelait ResultSet.getObject() plutôt que getString()?
  • Que se passerait-il si la ResultSet était obtenue par Statement.getResultSet()?

Pour votre code client, peu importe que vous appeliez JDBC d'une manière ou d'une autre, le résultat devrait toujours être le même. Si vous devez obligatoirement simulez la base de données (plutôt que d'utiliser une base de données de test, ou mieux, une approche basée sur testcontainers ), utilisez quelque chose comme jOOQ's MockDataProvider ou MockFileDatabase rendrait certainement les choses beaucoup plus simples. Dans ton cas:

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

L'approche ci-dessus fonctionnera indépendamment de la méthode Helper.getTablesName() avec le JDBC passé Connection.

Remarque: je travaille pour la société derrière jOOQ, cette réponse est donc biaisée.

1
Lukas Eder