我正在尝试在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<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之外调试代码时,这可以正常工作。我做错了什么或是不可能使用Robolectric测试SQlite数据库?
答案 0 :(得分:19)
Robolectric 2.3 使用SQLite的真实实现,而不是阴影和假货的集合。现在可以编写测试来验证真实的数据库行为。
答案 1 :(得分:10)
问题在于Robolectric的SQLiteDatabase仅存储在 内存,所以当你调用getReadableDatabase或getWritableDatabase时, 现有数据库将被新的空数据库覆盖。
我遇到了同样的问题而且我发现了解决方案 是我需要分叉Robolectric项目并补充说 如果给出两个相同的上下文,则使用ShadowSQLiteOpenHelper来保存数据库 倍。然而我叉子的问题是我必须'禁用' close() - 当给出上下文时的函数,否则 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 :(得分:2)
在接受的答案中链接的代码对我不起作用;它可能已经过时了。或许我的设置可能与众不同。我正在使用Robolectric 2.4快照,它似乎不包含ShadowSQLiteOpenHelper,除非我错过了什么。无论如何,我想出了一个解决方案。这是我做的:
@Config( shadows = { ShadowSQLiteOpenHelper.class } )
注释了我的测试类。无需自定义测试运行器。new Activity()
作为Context(Robolectric乐意照顾它),并且平常使用它。现在,在这一点上,我注意到实际的数据库文件是在本地创建的:在第一次运行使用我的SQLiteOpenHelper子类的测试之后,我在后续测试中不断得到SQLiteException,因为我的表已经存在;我可以在我的本地存储库中看到一个名为“path”的文件和一个名为“path-journal”的文件。这使我感到困惑,因为我认为影子类使用的是内存数据库。
事实证明,影子类中的违规行是:
database = SQLiteDatabase.openDatabase( "path", null, 0 );
getLadableDatabase()和getWriteableDatabase()中的。我知道真正的SQLiteOpenHelper可以创建一个内存数据库,在查看源代码以查看它是如何完成的之后,我将上面的代码替换为:
database = SQLiteDatabase.create( null );
之后,一切似乎都有效。我可以插入行并读回来。
希望这有助于其他人。
发生在我身上的一个奇怪的事情与这个问题并不完全相关,但可能会对某些人有所帮助,那就是我也在使用jmockit,而且我在同一个班级的一个测试中使用过它;但由于某种原因,这导致我的自定义阴影类不被使用。我转到了Mockito那个班级,它运作良好。