I have about ten tests on the ContentProvider that just uses SQLite; all pass save the two that pass through queryBuilder.query() in the Content Provider's query() method.
The methods being tested work in the real application!
This is with API 17 r2 and 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;
}
Here's the traceback:
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
Can plez tell if this is a limitation of Robolectric, or my bad? Many thanks!
P.S. Wouldn't it be dreamy if the Reflection API would put the failing class name in the InstantiationException message?
I had the same issue for my projects, and was finally able to solve it with some googling and the previous answer of U Avalos
@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);
}
}
@Config
annotation to your testTo use the custom shadow class, you can use the @Config
annotation in robolectric2
@RunWith(RobolectricTestRunner.class)
@Config( shadows = {CustomSQLiteShadow.class})
public class ContentProviderTest {
http://robolectric.blogspot.co.at/2013/05/configuring-robolectric-20.html
Android API 16 introduces this new method (that mtholdefer mentions):
public Cursor rawQueryWithFactory (SQLiteDatabase.CursorFactory cursorFactory, String sql, String[] selectionArgs, String editTable, CancellationSignal cancellationSignal)
As of 7/25/2013, roboelectric does NOT implement this method. However, it implements a similar method that doesn't use a CancellationSignal. Adding this method to ShadowSqlLiteDatabase made the problem go away for me:
@Implementation
public Cursor rawQueryWithFactory (SQLiteDatabase.CursorFactory cursorFactory,
String sql,
String[] selectionArgs,
String editTable,
CancellationSignal cancellationSignal)
{
return rawQueryWithFactory(cursorFactory,
sql,
selectionArgs,
editTable);
}
(Yes, you need to have roboelectric as a submodule. )
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!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With