Frage

Ich versuche, eine einfache SQLite -Datenbank mit Robolectric in meiner Android -Anwendung zu testen. Ich lege einige Werte ein, aber wenn ich sie zurücklies, werden 0 Zeilen zurückgegeben.

Ich verwende die SQLiteOpenHelper -Klasse, um auf die Datenbank zuzugreifen.

// RequestCache extends SQLiteOpenHelper
RequestCache cache = new RequestCache(activity); 
SQLiteDatabase db = cache.getWritableDatabase();

// Write to DB
ContentValues values = new ContentValues();
values.put(REQUEST_TIMESTAMP, TEST_TIME); 
values.put(REQUEST_URL, TEST_URL);
db.insertOrThrow(TABLE_NAME, null, values);

// Read from DB and compare values      
Vector<Request> matchingRequests = new Vector<Request>();
db = cache.getReadableDatabase();
Cursor cursor = db.query(TABLE_NAME, SEARCH_URL_RETURN_COLUMNS, SEARCH_URL_WHERE, new String[] {url}, null, null, ORDER_BY, null);
int id = 0;

while(cursor.moveToNext()) {
    long timestamp = cursor.getLong(0);
    Request request = new Request(id++);
    request.setUrl(url);
    request.setCreationTimestamp(new Date(timestamp));
    matchingRequests.add(request);
}


// Assert that one row is returned
assertThat(matchingRequests.size(), equalTo(1));  // fails, size() returns 0

Beim Debuggen des Code außerhalb von Robolectric funktioniert dies wie erwartet. Mache ich etwas falsch oder ist es nicht möglich, SQLite -Datenbanken mit Robolectric zu testen?

War es hilfreich?

Lösung

Hinweis: Diese Antwort ist veraltet. Wenn Sie Roboletric 2.x verwenden, sehen Sie sich bitte an https://stackoverflow.com/a/24578332/850787

Das Problem ist, dass die SQLitedAtabase von Robolectric nur im Speicher gespeichert ist. Wenn Sie also GetReadableDEldatabase oder getWritableableDatabase aufrufen, wird die vorhandene Datenbank mit einer neuen leeren Datenbank überschrieben.

Ich rannte zu dem gleichen Problem und nur eine Lösung, die ich fand, war, dass ich das robolektische Projekt aufweisen musste, und fügte ShadowsqliteOpenHelper hinzu, um Datenbank zu sparen, wenn der gleiche Kontext zweimal angegeben wird. Das Problem mit meiner Gabel ist jedoch, dass ich close ()-Funktion "deaktivieren" musste, wenn CONTEX angegeben ist, weil ansonsten Verbindung die Datenbank im Speicher zerstört. Ich habe Pull -Anfrage dafür gestellt, aber es wird noch nicht zu projizieren.

Aber zögern Sie nicht, meine Version zu klonen und es sollte Ihr Problem beheben (wenn ich sie richtig verstanden habe: P). Es kann auf Github gefunden werden: https://github.com/waltsu/robolectric

Hier finden Sie ein Beispiel, wie Sie die Änderung verwenden:

Context c = new Activity(); 
SQLiteOpenHelper helper = new SQLiteOpenHelper(c, "path", null, 1); 
SQLiteDatabase db = helper.getWritableDatabase(); 
// With the db write something to the database 
db.query(...); 
SQLiteOpenHelper helper2 = new SQLiteOpenHelper(c, "path", null, 1); 
SQLitedatabase db2 = helper2.getWritableDatabase(); 
// Now db and db2 is actually the same instance 
Cursor c = db2.query(...) ; // Fetch the data which was saved before 

Natürlich müssen Sie keinen neuen SQLiteOpenHelper erstellen, aber das ist nur ein Beispiel dafür, dass der gleiche Kontext an zwei verschiedene SQLiteOpenHelper die gleiche Datenbank liefert.

Andere Tipps

Robolectric 2.3 Verwendet eine echte Implementierung von SQLite anstelle einer Sammlung von Schatten und Fälschungen. Tests können jetzt geschrieben werden, um das reale Datenbankverhalten zu überprüfen.

Der in der akzeptierte Antwort verknüpfte Code funktionierte bei mir nicht; Es kann veraltet sein. Oder vielleicht ist mein Setup einfach anders. Ich verwende Robolectric 2.4 Snapshot, was anscheinend keinen ShadowsqliteopenHelper enthalten scheint, es sei denn, ich habe etwas verpasst. In jedem Fall habe ich eine Lösung herausgefunden. Hier ist, was ich getan habe:

  1. Ich habe eine Klasse namens ShadowsqliteopenHelper erstellt und den Inhalt des oben verlinkten Codes kopiert (https://github.com/waltsu/robolectric/blob/de2efdca39d26c5f18a3d278957b28a555119237/src/main/java/com/xtremelabs/ROBOLECTRIK/SHADOWS/SHADOWS/SHADOWS/SHADOWS/SHADOWS/SHADOWS/Shadows/shadows/shadows/shadows/shadows/Shadows/Shadows/Shadows) und fixierte die Importe.
  2. Befolgen der Anweisungen auf http://robolectric.org/custom-shadows/ Für die Verwendung benutzerdefinierter Schatten habe ich meine Testklasse mit Anmerkungen mit Anmerkungen mit Anmerkungen gemacht @Config( shadows = { ShadowSQLiteOpenHelper.class } ). Sie müssen keinen benutzerdefinierten Testläufer benötigen.
  3. In meinen Tests habe ich meine Unterklasse von Sqliteopenhelper instanziiert und in a vorbeigegangen new Activity() als Kontext (Robolectric kümmert sich glücklich darum) und benutzte ihn üblich.

Zu diesem Zeitpunkt bemerkte ich, dass eine tatsächliche Datenbankdatei lokal erstellt wurde: Nach dem ersten Lauf eines Tests, bei dem meine SQLiteOpenHelper -Unterklasse verwendet wurde, erhielt ich immer wieder eine SQLiteException zu nachfolgenden Tests, weil meine Tabelle bereits vorhanden war. Und ich konnte eine Datei namens "Path" und eine Datei namens "Pfadjournal" in meinem lokalen Repository sehen. Dies verwirrte mich, weil ich den Eindruck hatte, dass die Schattenklasse eine In-Memory-Datenbank verwendete.

Es stellt sich heraus, dass die beleidigende Linie in der Schattenklasse:

database = SQLiteDatabase.openDatabase( "path", null, 0 );

In beiden GetReadableableDatabase () und GetWriteAlteasAltedatabase (). Ich wusste, dass der echte Sqliteopenhelper eine In-Memory-Datenbank erstellen konnte, und nachdem ich mir die Quelle angesehen hatte, um zu sehen, wie sie fertig ist, habe ich die obige Zeile ersetzt durch:

database = SQLiteDatabase.create( null );

Danach scheint alles zu funktionieren. Ich kann Zeilen einfügen und zurück lesen.

Hoffentlich hilft das jemand anderem.

Eine seltsame Sache, die mir passiert ist, die nicht gerade mit dieser Frage zusammenhängt, aber jemandem weiter helfen könnte, ist, dass ich auch JMockit verwende und ich sie in einem Test in derselben Klasse verwendet hatte. Aber aus irgendeinem Grund führte dies dazu, dass meine benutzerdefinierte Schattenklasse nicht verwendet wurde. Ich bin für genau diese Klasse zu Mockito gewechselt und es funktioniert gut.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top