Вопрос

Я пытаюсь проверить простую базу данных SQLite, используя Robolectric в моем приложении Android. Я вкладываю некоторые значения, но при чтении их обратно 0 рядов возвращаются.

Я использую класс SQLiteOpenHelper для доступа к базе данных.

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

При отладте код вне robolectric работает, как и ожидалось. Я делаю что -то не так или невозможно проверить базы данных SQLite с помощью robolectric?

Это было полезно?

Решение

Примечание: этот ответ устарел. Если вы используете roboletric 2.x, пожалуйста, смотрите https://stackoverflow.com/a/24578332/850787

Проблема заключается в том, что SQLitedAtabase Robolectric хранится только в памяти, поэтому, когда вы вызовут getReadabledAtabase или getWritabledAtabase, существующая база данных будет переоценена с новой пустой базой данных.

Я сталкивался с той же проблемой, и только решение, которое я обнаружил, заключалось в том, что мне нужно было расколоть роболтрический проект и добавил ShadowsqliteopenHelper для сохранения базы данных, если тот же контекст дается два раза. Однако проблема с моей вилкой заключается в том, что мне пришлось «отключить» функцию Close ()-когда Contex дается, потому что в противном случае Connection.Close () разрушит базу данных в памяти. Я сделал запрос на это, но он еще не объединился с проектом.

Но не стесняйтесь клонировать мою версию, и она должна решить вашу проблему (если я правильно ее понял: P). Это можно найти на GitHub: https://github.com/waltsu/robolectric

Вот пример, как использовать модификацию:

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 

Конечно, вам не нужно создавать новый SQLiteOpenHelper, но это просто пример того, что передача того же контекста двум разным SQLiteOpenHelper даст ту же базу данных.

Другие советы

Роболтрик 2.3 Использует реальную реализацию SQLite вместо коллекции теней и подделок. Тесты теперь могут быть записаны для проверки реального поведения базы данных.

Код, связанный с принятым ответом, не сработал для меня; Это может быть устаревшим. Или, возможно, моя установка просто другая. Я использую снимки Robolectric 2.4, который, похоже, не включает в себя ShadowsqliteopenHelper, если только я что -то не пропустил. В любом случае я выяснил решение. Вот что я сделал:

  1. Я создал класс под названием ShadowsqliteopenHelper и копировал содержимое кода, связанного выше (https://github.com/waltsu/robolectric/blob/de2fdca39d26c5f18a3d278957b28a555119237/src/main/java/com/xtremelabs/robolectric/shadows/shadowskliteopenhel.jjjj) и исправил импорт.
  2. Следуя инструкциям на http://robolectric.org/custom-shadows/ Для использования пользовательских тени я аннотировал свой тестовый класс с помощью @Config( shadows = { ShadowSQLiteOpenHelper.class } ). Анкет Нет необходимости в пользовательском тестовом бегуне.
  3. В своих тестах я создал создание своего подкласса SQLiteOpenHelper, проходя в new Activity() Как контекст (Robolectric с радостью заботится об этом) и использовал его в обычном режиме.

Теперь, на данный момент, я заметил, что фактический файл базы данных создавался локально: после первого запуска теста, в котором использовался мой подкласс SQLiteOpenHelper, я продолжал получать SQLiteException при последующих тестах, потому что моя таблица уже существовала; И я мог видеть файл, называемый «Путь», и файл, называемый «Path-Journal», сидящий в моем локальном репозитории. Это смутило меня, потому что у меня было впечатление, что теневой класс использовал базу данных в памяти.

Оказывается, линия оскорбления в классе Shadow:

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

как в GetReadAbdATABASE () и GetWriteAbleblebase (). Я знал, что настоящий SQLiteOpenHelper может создать базу данных в памяти, и, посмотрев на источник, чтобы увидеть, как это сделано, я заменил вышеуказанную линию:

database = SQLiteDatabase.create( null );

После чего все, кажется, работает. Я могу вставить ряды и прочитать их обратно.

Надеюсь, это поможет кому -то еще.

Одна странная вещь, которая случилась со мной, которая не совсем связана с этим вопросом, но может помочь кому -то дальше, это то, что я также использую Jmockit, и я использовал его в одном тесте в том же классе; Но по какой -то причине это привело к тому, что мой пользовательский класс Shadow не использовался. Я переключился на Mockito только для этого класса, и он работает нормально.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top