Prueba de base de datos SQLite en Robolectric

Estoy tratando de probar una base de datos SQLite simple usando Robolectric en mi aplicación de Android. Estoy poniendo algunos valores, pero al leerlos se devuelven 0 filas.

Estoy utilizando la clase SQLiteOpenHelper para acceder a la base de datos.

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

Al depurar el código fuera de robolectric esto funciona como se esperaba. ¿Estoy haciendo algo malo o no es posible probar bases de datos SQlite usando Robolectric?

NOTA: Esta respuesta está obsoleta. Si está utilizando RoboLight 2.X, consulte https://stackoverflow.com/a/24578332/850787

El problema es que la base de datos SQLiteDatabase de Robolectric se almacena sólo en la memoria, por lo que cuando llama a getReadableDatabase o getWritableDatabase, la base de datos existente se reemplazará con nueva base de datos vacía.

Estaba funcionando al mismo problema y la única solución que encontré era que necesitaba fork el proyecto de Robolectric y agregado ShadowSQLiteOpenHelper para ahorrar la base de datos si el mismo contexto se da dos veces. Sin embargo el problema con mi tenedor es que tuve que 'disable' close () – función cuando se da el contexto porque de lo contrario Connection.close () destruirá la base de datos en la memoria. He hecho la petición del tirón para ella pero no se ha combinado al proyecto todavía.

Pero siéntase libre de clonar mi versión y debería solucionar su problema (si lo entendí correctamente: P). Se puede encontrar en GitHub: https://github.com/waltsu/robolectric

He aquí un ejemplo de cómo usar la modificación:

 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 

Por supuesto que no es necesario crear nuevo SQLiteOpenHelper, pero eso es sólo el ejemplo que pasando el mismo contexto a dos diferentes SQLiteOpenHelper dará la misma base de datos.

Robolectric 2.3 utiliza una implementación real de SQLite en lugar de una colección de sombras y falsificaciones. Ahora se pueden escribir pruebas para verificar el comportamiento real de la base de datos.

El código vinculado en la respuesta aceptada no funcionó para mí; Puede ser anticuado. O tal vez mi configuración es diferente. Estoy utilizando Robolectric 2.4 instantánea, que no parece incluir un ShadowSQLiteOpenHelper, a menos que me faltó algo. En cualquier caso, descubrí una solución. Esto es lo que hice:

  1. Creé una clase llamada ShadowSQLiteOpenHelper y copié el contenido del código enlazado arriba ( https://github.com/waltsu/robolectric/blob/de2efdca39d26c5f18a3d278957b28a555119237/src/main/java/com/xtremelabs/robolectric/shadows/ShadowSQLiteOpenHelper. Java ), y fijó las importaciones.
  2. Siguiendo las instrucciones en http://robolectric.org/custom-shadows/ para usar sombras personalizadas, @Config( shadows = { ShadowSQLiteOpenHelper.class } ) mi clase de prueba con @Config( shadows = { ShadowSQLiteOpenHelper.class } ) . No hay necesidad de un corredor de pruebas personalizado.
  3. En mis pruebas, instancié mi subclase de SQLiteOpenHelper, pasando en una new Activity() como el Contexto (Robolectric felizmente se ocupa de eso), y lo usé por costumbre.

Ahora, en este punto, me di cuenta de que un archivo de base de datos real se estaba creando localmente: después de la primera ejecución de una prueba que utiliza mi subclase SQLiteOpenHelper, seguí recibiendo una SQLiteException en las pruebas posteriores porque mi tabla ya existía; Y pude ver un archivo llamado "path" y un archivo llamado "path-journal" sentado en mi repositorio local. Esto me confundió porque estaba bajo la impresión de que la clase de sombra estaba usando una base de datos en memoria.

Resulta que la línea ofensiva en la clase shadow es:

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

En getReadableDatabase () y getWriteableDatabase (). Yo sabía que el verdadero SQLiteOpenHelper podría crear una base de datos en la memoria, y después de mirar la fuente para ver cómo se hace, he reemplazado la línea anterior con:

 database = SQLiteDatabase.create( null ); 

Después de lo cual, todo parece funcionar. Puedo insertar filas y leerlas de nuevo.

Espero que esto ayude a alguien más.

Una cosa extraña que me pasó que no está exactamente relacionada con esta pregunta, pero podría ayudar a alguien más, es que también estoy usando jmockit, y lo había utilizado en una prueba en la misma clase; Pero por alguna razón, esto hizo que mi clase de sombra personalizada no se utilizara. Cambié a Mockito por esa clase, y funciona bien.

  • Datos de SQLite a un RecyclerView
  • Intenta invocar el método virtual 'java.lang.Class java.lang.reflect.Field.getType ()' en una referencia de objeto nulo
  • Problema de corrupción de bases de datos precargado en la aplicación de Android
  • SQLite onUpgrade ()
  • Cómo obtener ArrayIndex fuera de límites Excepción al agregar nuevos elementos a la lista mientras se desplaza
  • Preguntas sobre el uso de Android Backup Service con una base de datos SQLite
  • Cómo almacenar y recuperar una matriz de bytes (datos de imagen) ay desde una base de datos SQLite?
  • Android Studios: Android Device Manager no muestra archivos para Nougat 7.0 en el Explorador de archivos
  • Cómo almacenar la base de datos sqlite directamente en sdcard
  • ¿Por qué un delete rawQuery necesita un moveToFirst para eliminar realmente las filas?
  • Diferencia entre las funciones window.openDatabase () y window.sqlitePlugin.openDatabase ()?
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.