Junit Mockito testen alles
Ich bin auf der Suche nach mehr Stunden jetzt ohne Ergebnis. Bitte um Hilfe...
Das ist meine Klasse zu testen:
public class DBSelectSchema extends Database {
private static final Logger LOG = Logger
.getLogger(DBSelectSchema.class.getName());
private Connection conn = null;
public DBSelectSchema() {
super();
}
/**
* This method will return the version of the database.
*
* @return version
* @throws Exception
*/
public JSONObject getVersionFromDB() throws SQLException {
ResultSet rs = null;
JSONObject version = new JSONObject();
PreparedStatement query = null;
try {
conn = mensaDB();
query = conn.prepareStatement("SELECT number FROM version");
rs = query.executeQuery();
if (rs.isBeforeFirst()) {
rs.next();
version.put(HTTP.HTTP, HTTP.OK);
version.put("version", rs.getString("number"));
} else {
version.put(HTTP.HTTP, HTTP.NO_CONTENT);
version.put(HTTP.ERROR, "Die SQL Abfrage lieferte kein Result!");
}
rs.close();
query.close();
conn.close();
} catch (SQLException sqlError) {
String message = ERROR.SQL_EXCEPTION;
LOG.log(Level.SEVERE, message, sqlError);
return version;
} catch (JSONException jsonError) {
String message = ERROR.JSON_EXCEPTION;
LOG.log(Level.SEVERE, message, jsonError);
return version;
}
return version;
}
Ich versuche, in jedem Zweig wird für 100% code-coverage.
Wie kann ich verspotte ResultSet rs, JSONObject version und PreparedStatement-Abfrage zu tun/return, was ich will:
Derzeit Teste ich so:
@Test
public void getVersionFromDB_RS_FALSE() throws SQLException, JSONException {
MockitoAnnotations.initMocks(this);
Mockito.when(dbSelMocked.mensaDB()).thenReturn(conn);
Mockito.when(conn.prepareStatement(Mockito.anyString())).thenReturn(query);
Mockito.when(query.executeQuery()).thenReturn(rs);
Mockito.when(rs.isBeforeFirst()).thenReturn(false);
JSONObject returnObj = dbSelMocked.getVersionFromDB();
assert(...);
}
Aber dies nur funktioniert, wenn die 3 Variablen sind Klassen-Variablen (wie Connection conn) und nicht-lokale Variablen. Aber ich möchte nicht, dass Sie (auch Zusammenhang) nicht global sein.
=== EDIT 1 ===
Es so funktioniert, wenn alle Variablen lokal:
@Test
public void getVersionFromDB_RS_FALSE() throws SQLException, JSONException {
System.out.println("####################");
System.out.println("started test: getVersionFromDB_RS_FALSE");
System.out.println("####################");
Connection conn = Mockito.mock(Connection.class);
PreparedStatement query = Mockito.mock(PreparedStatement.class);
ResultSet rs = Mockito.mock(ResultSet.class);
MockitoAnnotations.initMocks(this);
Mockito.when(dbSelMocked.mensaDB()).thenReturn(conn);
Mockito.when(conn.prepareStatement(Mockito.anyString())).thenReturn(query);
Mockito.when(query.executeQuery()).thenReturn(rs);
Mockito.when(rs.isBeforeFirst()).thenReturn(false);
JSONObject returnObj = dbSelMocked.getVersionFromDB();
assertTrue(returnObj.has("error"));
}
Aber ich bin nicht in der Lage zu verspotten JSONObject version in einem anderen test mehr 🙁
Wie kann ich das tun?
@Test
public void getVersionFromDB_JSON_EXCEPTION() throws SQLException, JSONException {
System.out.println("####################");
System.out.println("started test: getVersionFromDB_JSON_EXCEPTION");
System.out.println("####################");
JSONObject version = Mockito.mock(JSONObject.class);
MockitoAnnotations.initMocks(this);
doThrow(new JSONException("DBSelectSchemaIT THROWS JSONException")).when(version).put(anyString(), any());
JSONObject returnObj = dbSelMocked.getVersionFromDB();
System.out.println(returnObj.toString());
assertTrue(returnObj.equals(null));
}
Ich denke, die überschrieben werden, in der die wahre Methode... weil es nicht eine exception werfen und die Methode nicht scheitern.
- Ziel für 100% code coverage ist in der Regel eine komplette Verschwendung von Zeit. Schreiben von tests basierend auf den Anforderungen der Klasse, nicht auf der code-Zeilen, die es ausmachen.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Sind Sie unit testing data access layer, die von mocking alle ADO-Aufrufe. Indem Sie das tun, werden Sie am Ende mit einem unit-test nicht wirklich testen jeder Logik.
Nehmen ein Beispiel aus deinem code: angenommen, Sie verwenden die folgende sql-zum abrufen einer version Nummer :
SELECT number FROM version
. Nehmen wir jetzt an, dass die Spalte name geändert und Sie abrufen soll 2 zusätzliche Spalte aus der sql. Sie werden schließlich am Ende mit einer sql-wieSELECT number, newColumn1, newColumn2 FROM version
. Mit dem test, den Sie geschrieben hätte (mit mock), wäre es immer noch passieren, obwohl die nicht wirklich testen, ob die 2 neuen Spalte abgerufen wird. Erhalten Sie mein Punkt?Ich würde dir raten, einen Blick auf diese thread für einige mögliche alternative zu testen, Ihre data access layer. Mit mock für Ihre data-access-layer wird am Ende mit spröde-test, der nicht wirklich testen, alles
Ihre test-code hat mehrere Probleme.
Den ersten 2 Fragen kann gelöst werden, indem die Extraktion wiederholt code, um ein setup-Methode (ich fügte hinzu, statischen import für Mockito um den Lärm zu reduzieren):
Nun in jedem Ihrer tests, die Sie konfigurieren können
rs
zurückgeben, was Sie brauchen:Nun die wichtigste Frage: sind Sie spöttisch Klasse
DBSelectSchema
zurück Verbindung zu spotten. Mocking Klasse unter test kann dazu führen, dass andere hart-zu-spot-Probleme.Lösen diese Problem haben Sie 3 Optionen:
Umgestalten von code und Spritzen einige connection factory aus. So werden Sie
in der Lage zu verspotten, die es in Ihrem test.
Verlängern Klasse DBSelectSchema in der test-und überschreiben-Methode
mensaDB()
so wird es wieder verspottet VerbindungEmbedded Datenbank wie H2 und setzen Testdaten in 'Zahl' Tabelle
vor dem Aufruf getVersionFromDB()
Option #1
Extrakt-Erstellung der Verbindung zu einer separaten Klasse und verwenden Sie es in Ihrem
DBSelectSchema
:Dann Spritzen Sie es auf Ihrem DBSelectSchema:
Nun Ihren test können Sie real DBSelectSchema Klasse mit verspottet ConnectionFactory
Option #2
Können Sie machen fast echt Klasse unter test:
Option #3
Diese option ist für die meisten vorzuziehen, weil Sie call real SQL-Befehle, und Sie verspotten die gesamte Datenbank anstelle von Klassen. Es erfordert einige Anstrengungen, um plain-JDBC hier, aber es lohnt sich, dass. Beachten Sie, dass SQL-Dialekt kann sich von der DB in der Produktion eingesetzt.
Dann in den test-Sie einfach fügen Sie erforderlichen Datensätze an die DB:
Offensichtlich, DBSelectSchema muss den gleichen Anschluss verwenden, so können Sie in Kombination mit den Optionen #1 und #2,
Dein test ist viel zu groß, und Sie scheinen zu testen zu viel.
Teilen Sie Ihren code zusammen, es ist natürlich Pausen, so dass der Programmcode, der das abrufen der Daten ist getrennt von der Logik, die es bearbeitet.
Du nur wollen, testen Sie den code, den Sie schreiben, nicht die 3rd-party-code. Seine out-of-Spielraum für Ihre Bedürfnisse, und wenn Sie nicht Vertrauen können, dann verwenden Sie es nicht.