我应该测试内容提供商或内容解析器吗?

时间:2014-02-20 09:12:17

标签: android unit-testing android-strictmode

最近我在项目中启用了StrickMode,很多测试用例都失败了。 问题在于没有关闭Cursor。解决大多数失败并不难,但有一些我无法弄清楚。这个测试类有五个测试。由于我启用了严格模式,因此mMockContentResolver.query的每次调用都会失败并显示上面添加的消息。在测试结束时添加cursor.close()也不会改变任何东西。所以我想知道也许我应该使用MockContentProvider而不是MockContentResolver

更新:即使测试类只有测试testWithClosedCursor,它仍然在mMockContentResolver.query

上进行测试

MyProvider类看起来像这样,有7个表(我删除了这段代码,因为它看起来一样):

public class MyProvider extends ContentProvider {

private static UriMatcher sUriMatcher;

private static class DatabaseHelper extends SQLiteOpenHelper {

    public DatabaseHelper(Context context) {
        super(new ContextWrapper(context) {
            @Override
            public SQLiteDatabase openOrCreateDatabase(String name, int mode, SQLiteDatabase.CursorFactory factory) {

                File dir = new File(Taro.DATABASES_PATH);
                if (!dir.exists()) {
                    dir.mkdirs();
                }

                String databasePath = Taro.DATABASES_PATH + File.separator + name;
                return SQLiteDatabase.openDatabase(databasePath, null, SQLiteDatabase.CREATE_IF_NECESSARY);
            }
        }, DATABASE_NAME, null, DATABASE_VERSION);
    }

    @Override
    public void onCreate(SQLiteDatabase sqLiteDatabase) {
        DatabaseUpgrade.createTaskTemplatesTable(sqLiteDatabase);
    }

private DatabaseHelper mDatabaseHelper;

@Override
public boolean onCreate() {
    mDatabaseHelper = new DatabaseHelper(getContext());
    return true;
}

@Override
public Cursor query(Uri uri, String[] projection, String where, String[] whereArgs, String sortOrder) {
    SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
    String tableName;

    switch (sUriMatcher.match(uri)) {
        case TASK_TEMPLATES:
            qb.setProjectionMap(sTaskTemplatesProjectionMap);
            tableName = TASK_TEMPLATES_TABLE_NAME;
            break;
        case TASK_TEMPLATE_ID:
            qb.setProjectionMap(sTaskTemplatesProjectionMap);
            tableName = TASK_TEMPLATES_TABLE_NAME;
            break;
        default:
            throw new IllegalArgumentException(UNKNOWN_URI + uri);
    }
    qb.setTables(tableName);
    SQLiteDatabase db = mDatabaseHelper.getReadableDatabase();
    Cursor c = qb.query(db, projection, where, whereArgs, null, null, sortOrder);

    c.setNotificationUri(getContext().getContentResolver(), uri);
    return c;
}

@Override
public String getType(Uri uri) {
    switch (sUriMatcher.match(uri)) {
        case TASK_TEMPLATES:
            return TaskTemplatesContract.TaskTemplateColumns.CONTENT_TYPE;
        case TASK_TEMPLATE_ID:
            return TaskTemplatesContract.TaskTemplateColumns.CONTENT_ITEM_TYPE;
        default:
            throw new IllegalArgumentException(UNKNOWN_URI + uri);
    }
}

@Override
public Uri insert(Uri uri, ContentValues contentValues) {
    String table;
    Uri contentUri;

    switch (sUriMatcher.match(uri)) {
        case TASK_TEMPLATES:
            table = TASK_TEMPLATES_TABLE_NAME;
            contentUri = TaskTemplatesContract.TaskTemplateColumns.CONTENT_URI;
            break;
        default:
            throw new IllegalArgumentException(UNKNOWN_URI + uri);
    }

    ContentValues values;
    if (contentValues != null) {
        values = new ContentValues(contentValues);
    } else {
        values = new ContentValues();
    }

    SQLiteDatabase db = mDatabaseHelper.getWritableDatabase();
    long rowId = db.insert(table, null, values);
    if (rowId > 0) {
        Uri returnURI = ContentUris.withAppendedId(contentUri, rowId);
        getContext().getContentResolver().notifyChange(returnURI, null);
        return returnURI;
    }

    throw new SQLException("Failed to insert row into " + uri);
    }
}

测试类代码

public class MyProviderTestCase extends ProviderTestCase2<MyProvider> {
private MockContentResolver mMockContentResolver;
protected void setUp() throws java.lang.Exception {
    super.setUp();
    mMockContentResolver = getMockContentResolver();
}

public void testSomeTest() {
    final ContentValues contentValues = defaultTaskContentValues();

    final Uri uri = mMockContentResolver.insert(TaskTemplatesContract.TaskTemplateColumns.CONTENT_URI, contentValues);
    assertNotNull(uri);

    Cursor cursor = mMockContentResolver.query(TaskTemplatesContract.TaskTemplateColumns.CONTENT_URI, null, "ID=?", new String[]{TASK_ID}, null);
    assertEquals(1, cursor.getCount());

    contentValues.put(TaskTemplatesContract.TaskTemplateColumns.NAME, "View contact data.");

    int rowsUpdated = mMockContentResolver.update(TaskTemplatesContract.TaskTemplateColumns.CONTENT_URI, contentValues, "NAME=?", new String[]{TASK_NAME});
    assertEquals(1, rowsUpdated);

    cursor = mMockContentResolver.query(uri, null, null, null, null);
    assertTrue(cursor.moveToNext());
}

public void testWithClosedCursor() {
    final ContentValues contentValues = defaultTaskContentValues();
    final Uri uri = mMockContentResolver.insert(TaskTemplatesContract.TaskTemplateColumns.CONTENT_URI, contentValues);
    assertNotNull(uri);
    Cursor cursor = mMockContentResolver.query(TaskTemplatesContract.TaskTemplateColumns.CONTENT_URI, null, "ID=?", new String[]{TASK_ID}, null);
    assertEquals(1, cursor.getCount());
    cursor.close();
}

失败消息:

Finalizing a Cursor that has not been deactivated or closed. database = /mnt/sdcard/myapp/databases/job_templates.db, table = task_templates, query = SELECT position, id, instructions, _id, oid, name, form_id, type, job_id FROM task_templates WHERE (
    E/StrictMode(  493): android.database.sqlite.DatabaseObjectNotClosedException: Application did not close the cursor or database object that was opened here
    E/StrictMode(  493):    at android.database.sqlite.SQLiteCursor.<init>(SQLiteCursor.java:214)
    E/StrictMode(  493):    at android.database.sqlite.SQLiteDirectCursorDriver.query(SQLiteDirectCursorDriver.java:53)
    E/StrictMode(  493):    at android.database.sqlite.SQLiteDatabase.rawQueryWithFactory(SQLiteDatabase.java:1356)
    E/StrictMode(  493):    at android.database.sqlite.SQLiteQueryBuilder.query(SQLiteQueryBuilder.java:330)
    E/StrictMode(  493):    at android.database.sqlite.SQLiteQueryBuilder.query(SQLiteQueryBuilder.java:280)
    E/StrictMode(  493):    at org.my.app.databases.providers.MyProvider.query(MyProvider.java:244)
    E/StrictMode(  493):    at android.content.ContentProvider$Transport.query(ContentProvider.java:187)
    E/StrictMode(  493):    at android.content.ContentResolver.query(ContentResolver.java:262)
    E/StrictMode(  493):    at org.my.app.unit.MyProviderTestCase.testSomeTest(MyProviderTestCase.java:138)
    E/StrictMode(  493):    at java.lang.reflect.Method.invokeNative(Native Method)
    E/StrictMode(  493):    at java.lang.reflect.Method.invoke(Method.java:507)
    E/StrictMode(  493):    at junit.framework.TestCase.runTest(TestCase.java:154)
    E/StrictMode(  493):    at junit.framework.TestCase.runBare(TestCase.java:127)
    E/StrictMode(  493):    at junit.framework.TestResult$1.protect(TestResult.java:106)
    E/StrictMode(  493):    at junit.framework.TestResult.runProtected(TestResult.java:124)
    E/StrictMode(  493):    at junit.framework.TestResult.run(TestResult.java:109)
    E/StrictMode(  493):    at junit.framework.TestCase.run(TestCase.java:118)
    E/StrictMode(  493):    at android.test.AndroidTestRunner.runTest(AndroidTestRunner.java:169)
    E/StrictMode(  493):    at android.test.AndroidTestRunner.runTest(AndroidTestRunner.java:154)
    E/StrictMode(  493):    at android.test.InstrumentationTestRunner.onStart(InstrumentationTestRunner.java:529)
    E/StrictMode(  493):    at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:1448)
    W/System.err(  493): StrictMode VmPolicy violation with POLICY_DEATH; shutting down.

和StrictMode代码

    private void strictMode() {
    if (isDeveloperModeEnabled() && isRunningGingerbreadVersionOrHigher()) {
        StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
                .detectAll()
                .penaltyLog()
                .build());
        StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
                .detectLeakedSqlLiteObjects()
                .penaltyLog()
                .penaltyDeath()
                .build());
    }
}

有人有过类似的问题吗? 欢呼声。

0 个答案:

没有答案