6

我对只使用 SQLite 的 ContentProvider 进行了大约十次测试;all pass 保存在 Content Provider 的 query() 方法中通过 queryBuilder.query() 的两个。

正在测试的方法在实际应用程序中有效!

这适用于 API 17 r2 和 RoboLectric:robolectric-2.0-alpha-3-20130417.013705-46-jar-with-dependencies.jar

@Override
public Cursor query(Uri uri, String[] projection, String selection,
        String[] selectionArgs, String sortOrder) {
    Log.d(Constants.TAG, "MyContentProvider.query()");
    switch(matcher.match(uri)) {
    case ITEM: // OK
        selection = "_id = ?";
        selectionArgs = new String[]{ Long.toString(ContentUris.parseId(uri)) };
    case ITEMS: // OK
        break;
    default:
        throw new IllegalArgumentException("Did not recognize URI " + uri);
    }
    // build the query with SQLiteQueryBuilder
    SQLiteQueryBuilder qBuilder = new SQLiteQueryBuilder();
    qBuilder.setTables(TABLE_NAME);

    // query the database and get result in cursor
    final SQLiteDatabase db = mDatabase.getReadableDatabase();
    Cursor resultCursor = qBuilder.query(db,    // Line 112 in trace
            projection, selection, selectionArgs, null, null, sortOrder,
            null);
    resultCursor.setNotificationUri(getContext().getContentResolver(), uri);
    return resultCursor;
}

这是回溯:

java.lang.RuntimeException: java.lang.InstantiationException
    at org.robolectric.bytecode.ShadowWrangler.createShadowFor(ShadowWrangler.java:300)
    at org.robolectric.bytecode.ShadowWrangler.initializing(ShadowWrangler.java:74)
    at org.robolectric.bytecode.RobolectricInternals.initializing(RobolectricInternals.java:90)
    at android.database.sqlite.SQLiteQuery.$$robo$init(SQLiteQuery.java)
    at android.database.sqlite.SQLiteClosable.<init>(SQLiteClosable.java:26)
    at android.database.sqlite.SQLiteProgram.<init>(SQLiteProgram.java:41)
    at android.database.sqlite.SQLiteQuery.<init>(SQLiteQuery.java:37)
    at android.database.sqlite.SQLiteDirectCursorDriver.query(SQLiteDirectCursorDriver.java:44)
    at android.database.sqlite.SQLiteDatabase.rawQueryWithFactory(SQLiteDatabase.java:1314)
    at android.database.sqlite.SQLiteQueryBuilder.query(SQLiteQueryBuilder.java:400)
    at android.database.sqlite.SQLiteQueryBuilder.query(SQLiteQueryBuilder.java:333)
    at com.example.readingsprovider.ReadingsContentProvider.query(ReadingsContentProvider.java:112)
    at com.example.readingsprovider.test.ContentProviderTest.testUpdateMultipleWithoutWhere(ContentProviderTest.java:110)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
    at org.robolectric.RobolectricTestRunner$2.evaluate(RobolectricTestRunner.java:267)
    at org.junit.runners.BlockJUnit4ClassRunner.runNotIgnored(BlockJUnit4ClassRunner.java:79)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:71)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:49)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
    at org.robolectric.RobolectricTestRunner$1.evaluate(RobolectricTestRunner.java:202)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
Caused by: java.lang.InstantiationException
    at sun.reflect.InstantiationExceptionConstructorAccessorImpl.newInstance(InstantiationExceptionConstructorAccessorImpl.java:30)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
    at java.lang.Class.newInstance0(Class.java:357)
    at java.lang.Class.newInstance(Class.java:310)
    at org.robolectric.bytecode.ShadowWrangler.createShadowFor(ShadowWrangler.java:293)
    at org.robolectric.bytecode.ShadowWrangler.initializing(ShadowWrangler.java:74)
    at org.robolectric.bytecode.RobolectricInternals.initializing(RobolectricInternals.java:90)
    at android.database.sqlite.SQLiteQuery.$$robo$init(SQLiteQuery.java)
    at android.database.sqlite.SQLiteClosable.<init>(SQLiteClosable.java:26)
    at android.database.sqlite.SQLiteProgram.<init>(SQLiteProgram.java:41)
    at android.database.sqlite.SQLiteQuery.<init>(SQLiteQuery.java:37)
    at android.database.sqlite.SQLiteDirectCursorDriver.$$robo$$SQLiteDirectCursorDriver_7ac1_query(SQLiteDirectCursorDriver.java:44)
    at android.database.sqlite.SQLiteDirectCursorDriver.query(SQLiteDirectCursorDriver.java)
    at android.database.sqlite.SQLiteDatabase.$$robo$$SQLiteDatabase_ab15_rawQueryWithFactory(SQLiteDatabase.java:1314)
    at android.database.sqlite.SQLiteDatabase.rawQueryWithFactory(SQLiteDatabase.java)
    at android.database.sqlite.SQLiteQueryBuilder.$$robo$$SQLiteQueryBuilder_ba4d_query(SQLiteQueryBuilder.java:400)
    at android.database.sqlite.SQLiteQueryBuilder.query(SQLiteQueryBuilder.java)
    at android.database.sqlite.SQLiteQueryBuilder.$$robo$$SQLiteQueryBuilder_ba4d_query(SQLiteQueryBuilder.java:333)
    at android.database.sqlite.SQLiteQueryBuilder.query(SQLiteQueryBuilder.java)
    at com.example.readingsprovider.ReadingsContentProvider.query(ReadingsContentProvider.java:112)
    at com.example.readingsprovider.test.ContentProviderTest.testUpdateMultipleWithoutWhere(ContentProviderTest.java:110)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    ... 21 more

请问这是 Robolectric 的限制,还是我的错?非常感谢!

PS 如果反射 API 将失败的类名放在 InstantiationException 消息中,那不是很梦幻吗?

4

3 回答 3

7

我的项目也遇到了同样的问题,终于可以通过谷歌搜索和 U Avalos 的先前答案来解决它

1.创建自定义SQLiteShadow

@Implements(value = SQLiteDatabase.class, inheritImplementationMethods = true)
public class CustomSQLiteShadow extends ShadowSQLiteDatabase {

    @Implementation
    public Cursor rawQueryWithFactory (SQLiteDatabase.CursorFactory cursorFactory,
                                     String sql,
                                     String[] selectionArgs,
                                     String editTable,
                                     CancellationSignal cancellationSignal) {
      return rawQueryWithFactory(cursorFactory,
                                 sql,
                                 selectionArgs,
                                 editTable);
    }
}

2.@Config为您的测试添加注释

要使用自定义阴影类,可以使用@Configrobolectric2 中的注解

@RunWith(RobolectricTestRunner.class)
@Config( shadows = {CustomSQLiteShadow.class})
public class ContentProviderTest {

参考

http://robolectric.blogspot.co.at/2013/05/configuring-robolectric-20.html

于 2013-08-14T16:08:25.313 回答
2

Android API 16 引入了这种新方法(mtholdefer 提到过):

public Cursor rawQueryWithFactory (SQLiteDatabase.CursorFactory cursorFactory, String sql, String[] selectionArgs, String editTable, CancellationSignal cancellationSignal)

截至 2013 年 7 月 25 日,roboelectric 不实施此方法。但是,它实现了一个不使用 CancellationSignal 的类似方法。将此方法添加到 ShadowSqlLiteDatabase 使我的问题消失了:

@Implementation
public Cursor rawQueryWithFactory (SQLiteDatabase.CursorFactory cursorFactory,
                                 String sql,
                                 String[] selectionArgs,
                                 String editTable,
                                 CancellationSignal cancellationSignal)
{
  return rawQueryWithFactory(cursorFactory,
                             sql,
                             selectionArgs,
                             editTable);
}

(是的,您需要将 roboelectric 作为子模块。)

于 2013-07-26T02:48:52.643 回答
1

I have been running into a similar issue and I believe the problem is that SQLiteQueryBuilder is not supported in Robolectric. You can read more about that here. Basically the rawQueryWithFactor() method that SQLiteQueryBuilder uses is not overridden in ShadowSQLiteDatabase. Because of this the cusor is returned as null

I just started instantiating my cursors via SQLiteDatabaseInstance.query and that works perfectly in conjunction with Robolectric. Good luck and let me know if you find a more elegant solution do I can test my queryBuilders as well!

于 2013-06-20T11:48:41.737 回答