504 Stimmen

Das Mocken von statischen Methoden mit Mockito

Ich habe eine Fabrik geschrieben, um java.sql.Connection Objekte zu erzeugen:

public class MySQLDatabaseConnectionFactory implements DatabaseConnectionFactory {

    @Override public Connection getConnection() {
        try {
            return DriverManager.getConnection(...);
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }
}

Ich möchte die Parameter überprüfen, die an DriverManager.getConnection übergeben werden, aber ich weiß nicht, wie man eine statische Methode mockt. Ich benutze JUnit 4 und Mockito für meine Testfälle. Gibt es eine gute Möglichkeit, diesen speziellen Anwendungsfall zu mocken/überprüfen?

25voto

ChrisM Punkte 1148

Wie bereits erwähnt, können Sie mit Mockito keine statischen Methoden fälschen.

Wenn ein Wechsel Ihres Test-Frameworks keine Option ist, können Sie Folgendes tun:

Erstellen Sie ein Interface für DriverManager, fälschen Sie dieses Interface, injizieren Sie es über eine Art von Dependency Injection und überprüfen Sie darauf.

8voto

some random guy Punkte 390

Beobachtung: Wenn Sie eine statische Methode innerhalb einer statischen Entität aufrufen, müssen Sie die Klasse in @ PrepareForTest ändern.

Zum Beispiel:

securityAlgo = MessageDigest.getInstance(SECURITY_ALGORITHM);

Für den obigen Code, wenn Sie die MessageDigest-Klasse mocken müssen, verwenden Sie

@PrepareForTest(MessageDigest.class)

Wenn Sie jedoch etwas Ähnliches haben wie unten:

public class CustomObjectRule {

    object = DatatypeConverter.printHexBinary(MessageDigest.getInstance(SECURITY_ALGORITHM)
             .digest(message.getBytes(ENCODING)));

}

dann müssen Sie die Klasse vorbereiten, in der sich dieser Code befindet.

@PrepareForTest(CustomObjectRule.class)

Und dann mocken Sie die Methode:

PowerMockito.mockStatic(MessageDigest.class);
PowerMockito.when(MessageDigest.getInstance(Mockito.anyString()))
      .thenThrow(new RuntimeException());

7voto

Fermin Silva Punkte 3151

Sie können dies mit ein wenig Refactoring tun:

public class MySQLDatabaseConnectionFactory implements DatabaseConnectionFactory {

    @Override public Connection getConnection() {
        try {
            return _getConnection(... einige Parameter ...);
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }

    //Methode zum Weiterleiten von Parametern, um Mocking, Erweiterung usw. zu ermöglichen
    Connection _getConnection(... einige Parameter ...) throws SQLException {
        return DriverManager.getConnection(... einige Parameter ...);
    }
}

Dann können Sie Ihre Klasse MySQLDatabaseConnectionFactory erweitern, um eine gemockte Verbindung zurückzugeben, Assertions über die Parameter durchzuführen usw.

Die erweiterte Klasse kann innerhalb des Testfalls platziert werden, wenn sie sich im selben Paket befindet (was ich Ihnen empfehle)

public class MockedConnectionFactory extends MySQLDatabaseConnectionFactory {

    Connection _getConnection(... einige Parameter ...) throws SQLException {
        if (einige Parameter != etwas) throw new InvalidParameterException();

        //Erwägen Sie, einige Methoden mit when(yourMock.something()).thenReturn(value) zu mocken
        return Mockito.mock(Connection.class);
    }
}

7voto

iirekm Punkte 7639

Ich habe auch eine Kombination aus Mockito und AspectJ geschrieben: https://github.com/iirekm/varia/tree/develop/ajmock

Dein Beispiel wird zu:

when(() -> DriverManager.getConnection(...)).thenReturn(...);

6voto

Dupinder Singh Punkte 6087

Ich habe eine Lösung in Mockito gefunden. Diese Funktion ist nur ab der Version 3.4.0 verfügbar

https://asolntsev.github.io/en/2020/07/11/mockito-static-methods/

  • Abhängigkeit

    Ersetzen Sie in Ihrem build.gradle mockito-core:3.3.3 durch mockito-inline:3.4.0:

    testImplementation('org.mockito:mockito-inline:3.4.0')
  • Was werden wir mocken

     class Buddy 
     {
         static String name() 
         {
            return "John";
         }
     }
  • Mocke die statische Methode

        @Test
        void lookMomICanMockStaticMethods() 
        {
             assertThat(Buddy.name()).isEqualTo("John");
    
            try (MockedStatic theMock = Mockito.mockStatic(Buddy.class)) 
            {
                theMock.when(Buddy::name).thenReturn("Rafael");
                assertThat(Buddy.name()).isEqualTo("Rafael");
            }
    
            assertThat(Buddy.name()).isEqualTo("John");
        }

Ich denke, das könnte uns helfen.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X