Domanda

Sto cercando di testare un semplice database SQLite utilizzando Robolectric nella mia applicazione Android. Sto inserendo alcuni valori, ma quando le leggi indietro vengono restituite 0 righe.

Sto usando la classe SQLiteOPenHelper per accedere al database.

// 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

Durante il debug del codice al di fuori di Robolectric funziona come previsto. Sto facendo qualcosa di sbagliato o non è possibile testare i database SQLite usando robolettrico?

È stato utile?

Soluzione

Nota: questa risposta è obsoleta. Se stai usando Roboletric 2.x, consultare https://stackoverflow.com/a/24578332/850787

Il problema è che SQLiteDatabase di Robolectric viene archiviato solo in memoria, quindi quando si chiama GetReAdableAbletabase o getWritableAbleAtabase, il database esistente verrà sovrascritto da un nuovo database vuoto.

Stavo correndo con lo stesso problema e solo la soluzione che ho scoperto era che dovevo sborsare il progetto robolettrico e ho aggiunto Shadowwowsqliteopenhelper per salvare il database se lo stesso contesto è dato due volte. Tuttavia, il problema con la mia forcella è che ho dovuto "disabilitare" la funzione di chiusura () quando viene fornito contex perché altrimenti connessione.close () distruggerà il database in memoria. Ho fatto una richiesta pull ma non è ancora unito al progetto.

Ma sentiti libero di clonare la mia versione e dovrebbe risolvere il tuo problema (se l'ho capito correttamente: P). Può essere trovato su GitHub: https://github.com/waltsu/robolectric

Ecco un esempio come utilizzare la modifica:

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 

Ovviamente non è necessario creare un nuovo sqliteopenhelper, ma questo è solo un esempio che il passaggio dello stesso contesto a due diversi SQLiteopenhelper fornirà lo stesso database.

Altri suggerimenti

Robolettrico 2.3 Utilizza una vera implementazione di SQLite invece di una raccolta di ombre e falsi. I test possono ora essere scritti per verificare il comportamento del database reale.

Il codice collegato nella risposta accettata non ha funzionato per me; Potrebbe essere obsoleto. O forse la mia configurazione è solo diversa. Sto usando l'istantanea Robolectric 2.4, che non sembra includere un ShadowsQLiteopenhelper, a meno che non mi sia perso qualcosa. In ogni caso, ho capito una soluzione. Ecco cosa ho fatto:

  1. Ho creato una classe chiamata ShadowwsQLiteOpenhelper e ho messo in mostra il contenuto del codice collegato sopra (https://github.com/waltsu/robolectric/blob/de2efdca39d26c5f18a3d278957b28a555119237/src/main/java/com/xtremelabs/robolectric/shadows/shadowsqliteopenhelper.java) e risolto le importazioni.
  2. Seguendo le istruzioni su http://robolectric.org/custom-shadows/ Per l'uso di ombre personalizzate, ho annotato la mia classe di test @Config( shadows = { ShadowSQLiteOpenHelper.class } ). Non è necessario un runner di prova personalizzato.
  3. Nei miei test, ho istanziato la mia sottoclasse di sqliteopenhelper, passando in a new Activity() come il contesto (robolettrico si occupa felicemente di quello) e lo usava al solito.

Ora, a questo punto, ho notato che un file di database effettivo veniva creato localmente: dopo la prima esecuzione di un test che utilizzava la mia sottoclasse SQLiteOopenhelper, continuavo a ottenere un SQLiteException sui test successivi perché la mia tabella esisteva già; E ho potuto vedere un file chiamato "Path" e un file chiamato "Path-Journal" seduto nel mio repository locale. Questo mi ha confuso perché avevo l'impressione che la classe Shadow stesse usando un database in memoria.

Si scopre che la linea offensiva nella classe ombra è:

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

Sia in GetReAdableAdatabase () che GetWriteAbletabase (). Sapevo che il vero sqliteopenhelper poteva creare un database in memoria e dopo aver guardato la fonte per vedere come è stato fatto, ho sostituito la linea sopra con:

database = SQLiteDatabase.create( null );

Dopodiché, tutto sembra funzionare. Sono in grado di inserire le righe e leggerle indietro.

Spero che questo aiuti qualcun altro.

Una cosa strana che mi è successa che non è esattamente correlata a questa domanda, ma potrebbe aiutare più a qualcuno, è che sto usando anche JMockit e l'ho usato in un test nella stessa classe; Ma per qualche motivo, ciò ha causato l'utilizzo della mia classe di ombra personalizzata. Sono passato a Mockito solo per quella classe e funziona bene.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top