目前我为它编写了一个Provider和TestCase。到目前为止一切都很顺利,现在我试着测试一下通知是否像预期的那样工作。基本上,我创建了一个contenttobserver,并在我的观察者上执行插入操作。所有的插入都工作得很好,我只是在通知问题上挣扎。为此,我在我的ProviderTestCase中使用CountDownlatch,当任何#onChange方法被调用时,它会得到count down:
@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结束于Insert的/ID。
我不确定我是否在那里创建了某种死锁,因为Latch等待并且提供者不能使用notifyChange方法调用Observer方法。因此,在5秒后,测试失败,因为超时发生了。
实际情况是,您创建的Handler绑定到测试线程,因此您永远不会收到回调。你需要使用loop。getMainLooper获取对主(线程)处理程序的引用:
<>之前
new Handler(Looper.getMainLooper());
之前其他建议,在resolver.insert()之前调用observer.latch.await(),以避免在调用await()之前发生回调时出现不稳定的测试。
用@MediumTest或@LargeTest注释这个测试。您应该只在单元测试中使用@SmallTest。
使用assertTrue(observer.latch.getCount() <= 0)在这种情况下更容易读,或者如果你想坚持hamcrest匹配器,assertThat(observer.latch.getCount(), equalTo(0L));