下面是一个示例测试,它使用 getContentResolver().query 从内容提供者返回模拟数据。
它应该适用于任何内容提供者,只需进行一些修改,但此示例模拟从联系人内容提供者返回的电话号码
以下是一般步骤:
- 使用 MatrixCursor 创建适当的光标
- 扩展 MockContentProvider 以返回创建的游标
- 使用 addProvider 和 setContentResolver 将提供程序添加到 MockContentResolver
- 将 MockContentResolver 添加到扩展的 MockContext
- 将上下文传递给被测类
因为 query 是 final 方法,所以你不仅需要 mock MockContentProvider,还需要 mock MockContentResolver。否则在查询方法中调用acquireProvider时会报错。
这是示例代码:
public class MockContentProviderTest extends AndroidTestCase{
public void testMockPhoneNumbersFromContacts(){
//Step 1: Create data you want to return and put it into a matrix cursor
//In this case I am mocking getting phone numbers from Contacts Provider
String[] exampleData = {"(979) 267-8509"};
String[] examleProjection = new String[] { ContactsContract.CommonDataKinds.Phone.NUMBER};
MatrixCursor matrixCursor = new MatrixCursor(examleProjection);
matrixCursor.addRow(exampleData);
//Step 2: Create a stub content provider and add the matrix cursor as the expected result of the query
HashMapMockContentProvider mockProvider = new HashMapMockContentProvider();
mockProvider.addQueryResult(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, matrixCursor);
//Step 3: Create a mock resolver and add the content provider.
MockContentResolver mockResolver = new MockContentResolver();
mockResolver.addProvider(ContactsContract.AUTHORITY /*Needs to be the same as the authority of the provider you are mocking */, mockProvider);
//Step 4: Add the mock resolver to the mock context
ContextWithMockContentResolver mockContext = new ContextWithMockContentResolver(super.getContext());
mockContext.setContentResolver(mockResolver);
//Example Test
ExampleClassUnderTest underTest = new ExampleClassUnderTest();
String result = underTest.getPhoneNumbers(mockContext);
assertEquals("(979) 267-8509",result);
}
//Specialized Mock Content provider for step 2. Uses a hashmap to return data dependent on the uri in the query
public class HashMapMockContentProvider extends MockContentProvider{
private HashMap<Uri, Cursor> expectedResults = new HashMap<Uri, Cursor>();
public void addQueryResult(Uri uriIn, Cursor expectedResult){
expectedResults.put(uriIn, expectedResult);
}
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder){
return expectedResults.get(uri);
}
}
public class ContextWithMockContentResolver extends RenamingDelegatingContext {
private ContentResolver contentResolver;
public void setContentResolver(ContentResolver contentResolver){ this.contentResolver = contentResolver;}
public ContextWithMockContentResolver(Context targetContext) { super(targetContext, "test");}
@Override public ContentResolver getContentResolver() { return contentResolver; }
@Override public Context getApplicationContext(){ return this; } //Added in-case my class called getApplicationContext()
}
//An example class under test which queries the populated cursor to get the expected phone number
public class ExampleClassUnderTest{
public String getPhoneNumbers(Context context){//Query for phone numbers from contacts
String[] projection = new String[]{ ContactsContract.CommonDataKinds.Phone.NUMBER};
Cursor cursor= context.getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, projection, null, null, null);
cursor.moveToNext();
return cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
}
}
}
如果您不想传递上下文:
如果你想让它在被测类中由 getContext() 返回而不是传递它,你应该能够像这样在你的 android 测试中覆盖 getContext()
@Override
public Context getContext(){
return new ContextWithMockContentResolver(super.getContext());
}