以下は、getContentResolver().query を使用してコンテンツ プロバイダーからモック データを返すテストの例です。
いくつかの変更を加えると、どのコンテンツ プロバイダーでも機能するはずですが、この例では、Contacts コンテンツ プロバイダーから返される電話番号を模擬しています。
一般的な手順は次のとおりです。
- MatrixCursor を使用して適切なカーソルを作成します
- MockContentProvider を拡張して作成したカーソルを返す
- addProvider と setContentResolver を使用してプロバイダーを MockContentResolver に追加する
- MockContentResolver を拡張 MockContext に追加する
- テスト対象のクラスにコンテキストを渡します
query は final メソッドなので、MockContentProvider だけでなく MockContentResolver もモックする必要があります。そうしないと、query メソッドで 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());
}