Robolectric 访问数据库出错
Robolectric accessing database throws an error
我有一个创建 activity 的测试,它试图从数据库中获取一些数据。 SQLiteException
失败
17:40:40.528 [DEBUG] [TestEventLogger] android.database.sqlite.SQLiteException: Cannot open SQLite connection, base error code: 14
17:40:40.528 [DEBUG] [TestEventLogger] at org.robolectric.shadows.ShadowSQLiteConnection.rethrow(ShadowSQLiteConnection.java:53)
17:40:40.528 [DEBUG] [TestEventLogger] at org.robolectric.shadows.ShadowSQLiteConnection.access0(ShadowSQLiteConnection.java:30)
17:40:40.529 [DEBUG] [TestEventLogger] at org.robolectric.shadows.ShadowSQLiteConnection$Connections.execute(ShadowSQLiteConnection.java:443)
17:40:40.529 [DEBUG] [TestEventLogger] at org.robolectric.shadows.ShadowSQLiteConnection$Connections.open(ShadowSQLiteConnection.java:345)
17:40:40.529 [DEBUG] [TestEventLogger] at org.robolectric.shadows.ShadowSQLiteConnection.nativeOpen(ShadowSQLiteConnection.java:58)
17:40:40.529 [DEBUG] [TestEventLogger] at android.database.sqlite.SQLiteConnection.nativeOpen(SQLiteConnection.java)
17:40:40.529 [DEBUG] [TestEventLogger] at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:209)
17:40:40.529 [DEBUG] [TestEventLogger] at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:193)
17:40:40.529 [DEBUG] [TestEventLogger] at android.database.sqlite.SQLiteConnectionPool.openConnectionLocked(SQLiteConnectionPool.java:463)
17:40:40.530 [DEBUG] [TestEventLogger] at android.database.sqlite.SQLiteConnectionPool.open(SQLiteConnectionPool.java:185)
17:40:40.530 [DEBUG] [TestEventLogger] at android.database.sqlite.SQLiteConnectionPool.open(SQLiteConnectionPool.java:177)
17:40:40.530 [DEBUG] [TestEventLogger] at android.database.sqlite.SQLiteDatabase.openInner(SQLiteDatabase.java:806)
17:40:40.530 [DEBUG] [TestEventLogger] at android.database.sqlite.SQLiteDatabase.open(SQLiteDatabase.java:791)
17:40:40.530 [DEBUG] [TestEventLogger] at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:694)
17:40:40.530 [DEBUG] [TestEventLogger] at android.app.ContextImpl.openOrCreateDatabase(ContextImpl.java:1142)
17:40:40.530 [DEBUG] [TestEventLogger] at android.content.ContextWrapper.openOrCreateDatabase(ContextWrapper.java:267)
17:40:40.531 [DEBUG] [TestEventLogger] at android.database.sqlite.SQLiteOpenHelper.getDatabaseLocked(SQLiteOpenHelper.java:223)
17:40:40.531 [DEBUG] [TestEventLogger] at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:163)
在我将数据库 class 移至单例模型之前,这曾经工作得很好。关于如何用 Robolectric 处理这个问题有什么建议吗?我找不到任何关于此的文档或示例。
编辑:
运行 Robolectric 3.0 RC-2
Robolectric 正在驱动我的 activity,它试图对数据库进行一些处理。
在我的应用程序数据库 class 中,从 'fixes' 问题下方删除对实例 == null 的检查(即 Robolectric 运行 没有问题,测试是否每次都重新创建 MySQLiteOpenHelper时间)
public static synchronized MyDataManager getInstance(Context context){
if (sInstance == null) {
sInstance = new MyDataManager(context.getApplicationContext());
}
return sInstance;
}
private MyDataManager(Context context) {
dbHelper = new MySQLiteOpenHelper(context);
}
MySQLiteOpenHelper 是 SQLiteOpenHelper 的简单扩展。
失败发生在(再次,这是由 db class):
database = dbHelper.getWritableDatabase();
显然我真的不想每次都在我的应用程序中重新创建连接 - 我认为没有人会想要那样吗?这让我觉得在 Robolectric 中应该有一种方法可以正确地做到这一点,我只是在这里错过了一个技巧?
编辑:
此外,测试在隔离状态下成功运行,这让我认为这与 Robolectric 在测试用例之间移动并重用数据库连接有关?
这两个测试都不做任何特定于数据库或与任何数据库 classes 相关的事情。第一个测试启动一个片段,它将访问数据库以写入一些数据。第二次测试未能如上所示尝试打开数据库。
IMO 你必须 remove/replace 数据库 usage/singlethons 依赖注入并在测试中模拟它们。在这种情况下,您不需要实例化 code/tests.
中未使用的内容
听起来像是空洞的建议,而且比 "just to fix current state" 需要更多的努力。但我的经验是值得做的,它将导致整个应用程序的清晰设计和测试。
对我来说,它相当于(对于明显的例子再次抱歉):
Debug
对比 Unit testing
- 修复 OEM 以防止内存泄漏
在每次测试之间重置所有单例实例,否则您会遇到像您一样的副作用。
@After
public void finishComponentTesting() {
resetSingleton(YourSQLiteOpenHelper.class, "sInstance");
}
private void resetSingleton(Class clazz, String fieldName) {
Field instance;
try {
instance = clazz.getDeclaredField(fieldName);
instance.setAccessible(true);
instance.set(null, null);
} catch (Exception e) {
throw new RuntimeException();
}
}
我有一个创建 activity 的测试,它试图从数据库中获取一些数据。 SQLiteException
失败17:40:40.528 [DEBUG] [TestEventLogger] android.database.sqlite.SQLiteException: Cannot open SQLite connection, base error code: 14
17:40:40.528 [DEBUG] [TestEventLogger] at org.robolectric.shadows.ShadowSQLiteConnection.rethrow(ShadowSQLiteConnection.java:53)
17:40:40.528 [DEBUG] [TestEventLogger] at org.robolectric.shadows.ShadowSQLiteConnection.access0(ShadowSQLiteConnection.java:30)
17:40:40.529 [DEBUG] [TestEventLogger] at org.robolectric.shadows.ShadowSQLiteConnection$Connections.execute(ShadowSQLiteConnection.java:443)
17:40:40.529 [DEBUG] [TestEventLogger] at org.robolectric.shadows.ShadowSQLiteConnection$Connections.open(ShadowSQLiteConnection.java:345)
17:40:40.529 [DEBUG] [TestEventLogger] at org.robolectric.shadows.ShadowSQLiteConnection.nativeOpen(ShadowSQLiteConnection.java:58)
17:40:40.529 [DEBUG] [TestEventLogger] at android.database.sqlite.SQLiteConnection.nativeOpen(SQLiteConnection.java)
17:40:40.529 [DEBUG] [TestEventLogger] at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:209)
17:40:40.529 [DEBUG] [TestEventLogger] at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:193)
17:40:40.529 [DEBUG] [TestEventLogger] at android.database.sqlite.SQLiteConnectionPool.openConnectionLocked(SQLiteConnectionPool.java:463)
17:40:40.530 [DEBUG] [TestEventLogger] at android.database.sqlite.SQLiteConnectionPool.open(SQLiteConnectionPool.java:185)
17:40:40.530 [DEBUG] [TestEventLogger] at android.database.sqlite.SQLiteConnectionPool.open(SQLiteConnectionPool.java:177)
17:40:40.530 [DEBUG] [TestEventLogger] at android.database.sqlite.SQLiteDatabase.openInner(SQLiteDatabase.java:806)
17:40:40.530 [DEBUG] [TestEventLogger] at android.database.sqlite.SQLiteDatabase.open(SQLiteDatabase.java:791)
17:40:40.530 [DEBUG] [TestEventLogger] at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:694)
17:40:40.530 [DEBUG] [TestEventLogger] at android.app.ContextImpl.openOrCreateDatabase(ContextImpl.java:1142)
17:40:40.530 [DEBUG] [TestEventLogger] at android.content.ContextWrapper.openOrCreateDatabase(ContextWrapper.java:267)
17:40:40.531 [DEBUG] [TestEventLogger] at android.database.sqlite.SQLiteOpenHelper.getDatabaseLocked(SQLiteOpenHelper.java:223)
17:40:40.531 [DEBUG] [TestEventLogger] at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:163)
在我将数据库 class 移至单例模型之前,这曾经工作得很好。关于如何用 Robolectric 处理这个问题有什么建议吗?我找不到任何关于此的文档或示例。
编辑:
运行 Robolectric 3.0 RC-2
Robolectric 正在驱动我的 activity,它试图对数据库进行一些处理。 在我的应用程序数据库 class 中,从 'fixes' 问题下方删除对实例 == null 的检查(即 Robolectric 运行 没有问题,测试是否每次都重新创建 MySQLiteOpenHelper时间)
public static synchronized MyDataManager getInstance(Context context){
if (sInstance == null) {
sInstance = new MyDataManager(context.getApplicationContext());
}
return sInstance;
}
private MyDataManager(Context context) {
dbHelper = new MySQLiteOpenHelper(context);
}
MySQLiteOpenHelper 是 SQLiteOpenHelper 的简单扩展。
失败发生在(再次,这是由 db class):
database = dbHelper.getWritableDatabase();
显然我真的不想每次都在我的应用程序中重新创建连接 - 我认为没有人会想要那样吗?这让我觉得在 Robolectric 中应该有一种方法可以正确地做到这一点,我只是在这里错过了一个技巧?
编辑:
此外,测试在隔离状态下成功运行,这让我认为这与 Robolectric 在测试用例之间移动并重用数据库连接有关?
这两个测试都不做任何特定于数据库或与任何数据库 classes 相关的事情。第一个测试启动一个片段,它将访问数据库以写入一些数据。第二次测试未能如上所示尝试打开数据库。
IMO 你必须 remove/replace 数据库 usage/singlethons 依赖注入并在测试中模拟它们。在这种情况下,您不需要实例化 code/tests.
中未使用的内容听起来像是空洞的建议,而且比 "just to fix current state" 需要更多的努力。但我的经验是值得做的,它将导致整个应用程序的清晰设计和测试。
对我来说,它相当于(对于明显的例子再次抱歉):
Debug
对比Unit testing
- 修复 OEM 以防止内存泄漏
在每次测试之间重置所有单例实例,否则您会遇到像您一样的副作用。
@After
public void finishComponentTesting() {
resetSingleton(YourSQLiteOpenHelper.class, "sInstance");
}
private void resetSingleton(Class clazz, String fieldName) {
Field instance;
try {
instance = clazz.getDeclaredField(fieldName);
instance.setAccessible(true);
instance.set(null, null);
} catch (Exception e) {
throw new RuntimeException();
}
}