在Robolectric中测试SQLite数据库

我正试图在我的Android应用程序中使用Robolectric测试一个简单的SQLite数据库。 我正在输入一些值,但在读取它们时会返回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 matchingRequests = new Vector(); 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之外调试代码时,这可以按预期工作。 我做错了什么或是不可能使用Robolectric测试SQlite数据库?

注意:此答案已过时。 如果您使用的是Roboletric 2.X,请参阅https://stackoverflow.com/a/24578332/850787

问题是Robolectric的SQLiteDatabase只存储在内存中,因此当您调用getReadableDatabase或getWritableDatabase时,现有数据库将被新的空数据库覆盖。

我遇到了同样的问题,我发现只有解决方案是我需要分叉Robolectric项目并添加ShadowSQLiteOpenHelper来保存数据库,如果给出两次相同的上下文。 然而我的fork的问题是我必须’禁用’close() – 函数在给出contex时因为否则Connection.close()会破坏内存中的数据库。 我已经提出拉取请求,但它尚未合并到项目中。

但随意克隆我的版本,它应该解决你的问题(如果我理解正确:P)。 它可以在GitHub上find: 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的示例,它将提供相同的数据库。

Robolectric 2.3使用SQLite的实际实现,而不是阴影和假货的集合。 现在可以编写测试来validation真实的数据库行为。

接受的答案中链接的代码对我不起作用; 它可能已经过时了。 或许我的设置可能与众不同。 我正在使用Robolectric 2.4快照,它似乎不包含ShadowSQLiteOpenHelper,除非我错过了什么。 无论如何,我想出了一个解决方案。 这是我做的:

  1. 我创建了一个名为ShadowSQLiteOpenHelper的类,并复制粘贴上面链接的代码的内容( https://github.com/waltsu/robolectric/blob/de2efdca39d26c5f18a3d278957b28a555119237/src/main/java/com/xtremelabs/robolectric/shadows/ShadowSQLiteOpenHelper。 java ),并修复了导入。
  2. 按照http://robolectric.org/custom-shadows/上有关使用自定义阴影的说明,我使用@Config( shadows = { ShadowSQLiteOpenHelper.class } )注释了我的测试类。 无需自定义测试运行器。
  3. 在我的测试中,我实例化了我的SQLiteOpenHelper的子类,传递了一个new Activity()作为Context(Robolectric乐意照顾它),并按常规使用它。

现在,在这一点上,我注意到实际的数据库文件是在本地创建的:在第一次运行使用我的SQLiteOpenHelper子类的测试之后,我在后续测试中不断得到SQLiteException,因为我的表已经存在; 我可以在我的本地存储库中看到一个名为“path”的文件和一个名为“path-journal”的文件。 这让我很困惑,因为我的印象是影子类使用的是内存数据库。

事实certificate,影子类中的违规行是:

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

在getReadableDatabase()和getWriteableDatabase()中。 我知道真正的S​​QLiteOpenHelper可以创建一个内存数据库,在查看源代码以查看它是如何完成的之后,我将上面的代码替换为:

 database = SQLiteDatabase.create( null ); 

之后,一切似乎都有效。 我能够插入行并读回来。

希望这有助于其他人。

发生在我身上的一个奇怪的事情与这个问题并不完全相关,但可能会对某些人有所帮助,那就是我也在使用jmockit,而且我在同一个类中的一个测试中使用过它; 但由于某种原因,这导致我的自定义阴影类不被使用。 我转到了Mockito那个class级,它运作正常。