ProviderTestCase测试通知URI

时间:2014-03-26 00:58:29

标签: android android-contentprovider android-testing

目前我为它编写了一个Provider和TestCase。它到目前为止进展顺利,现在我尝试测试通知是否按预期工作。基本上我创建一个ContentObserver并在我的Observer上进行插入。所有插入工作正常,我只是在努力解决通知问题。为此,我在ProviderTestCase中使用CountDownlatch,当调用任何#onChange方法时,它会倒计时:

@SmallTest
public void testUriNotification() throws Exception
{
    final TestContentObserver observer = new TestContentObserver(new Handler(), 1);
    resolver.registerContentObserver(FavoritesContract.Favorites.CONTENT_URI,true,observer);
    final ContentValues values = FavoritesContract.createFavorite(1);
    final Uri uri = resolver.insert(FavoritesContract.Favorites.CONTENT_URI, values);
    assertNotNull(uri);

    observer.latch.await(5, TimeUnit.SECONDS);
    assertThat(observer.latch.getCount(), Matchers.is(0L));

    resolver.unregisterContentObserver(observer);
}

public static class TestContentObserver extends ContentObserver
{
    private CountDownLatch latch;

    public TestContentObserver(final Handler handler, final int countDown)
    {
        super(handler);
        latch = new CountDownLatch(countDown);
    }

    @Override
    public boolean deliverSelfNotifications()
    {
        return true;
    }

    @Override
    public void onChange(final boolean selfChange)
    {
        latch.countDown();
        super.onChange(selfChange);
    }

    @Override
    public void onChange(final boolean selfChange, final Uri uri)
    {
        latch.countDown();
        super.onChange(selfChange, uri);
    } 

插入方法如下:

@Override
public Uri insert(final Uri uri, final ContentValues values)
{
    if (!insertAllowed(uri))
    {
        throw new IllegalArgumentException("Unsupported URI:" + uri);
    }

    final SQLiteDatabase db = database.getWritableDatabase();

    if (isFavoriteItem(uri))
    {
        final long id = db.insert("favorites", null, values);
        return getUriForId(id, uri);
    }
    else if (isFavoriteList(uri))
    {
        final long id = db.insert("favorites", null, values);
        return getUriForId(id, uri);
    }
    throw new IllegalArgumentException("No matching URI found for:" + uri);
}

private Uri getUriForId(long id, Uri uri)
{
    Log.d(LOG_TAG,"getUriForId:"+id+" uri:"+uri);
    if (id > 0)
    {
        final Uri itemUri = ContentUris.withAppendedId(uri, id);
        if (!isInBatchMode())
        {
            // notify all listeners of changes and return itemUri:
            Log.d(LOG_TAG, "Notify ContentResolver using :" + uri.toString());
            getContext().
                    getContentResolver().
                    notifyChange(itemUri, null);
        }
        else
        {
            Log.d(LOG_TAG, "Cant notify ContentResolver, we are in Batch Mode for :" + uri.toString());
        }
        return itemUri;
    }
    return null;
}
private final boolean insertAllowed(final Uri uri)
{
    if (uri == null)
    {
        return false;
    }
    return ALLOWED_TYPES.contains(URI_MATCHER.match(uri));
}

private final boolean isFavoriteList(final Uri uri)
{
    if (uri == null)
    {
        return false;
    }
    return URI_MATCHER.match(uri) == FAVORITE_LIST;
}

private final boolean isFavoriteItem(final Uri uri)
{
    if (uri == null)
    {
        return false;
    }
    return URI_MATCHER.match(uri) == FAVORITE_ID;
}

所以,CountDownlatch永远不会倒计时。我看到在getUriForId方法中,URI看起来很好。 URI结束插入的/ ID。

我不确定我是否在那里创建了某种死锁,因为Latch等待并且提供者无法使用notifyChange方法调用Observer方法。因此,在5秒后测试失败,因为超时发生了。

1 个答案:

答案 0 :(得分:0)

发生的事情是您创建的处理程序绑定到测试线程,因此您永远不会收到回调。您需要使用Looper.getMainLooper来获取对主(线程)处理程序的引用:


new Handler(Looper.getMainLooper());

其他建议,在resolver.insert()之前调用observer.latch.await(),以避免在调用await()之前发生回调时的片状测试。

使用@MediumTest或@LargeTest注释此测试。您应该只使用@SmallTest进行单元测试。

使用assertTrue(observer.latch.getCount()< = 0),在这种情况下更易读,或者你想坚持使用hamcrest Matchers,assertThat(observer.latch.getCount(),equalTo(0L));