pix*_*xel 9 android unit-testing final android-contentresolver
我正在尝试测试查询内容解析器的类.
我想用MockContentResolver和模拟query方法.
问题是这种方法是最终的.我该怎么办?使用模拟框架?模拟其他课程?提前致谢.
public class CustomClass {
private ContentResolver mContentResolver;
public CustomClass(ContentResolver contentResolver) {
mContentResolver = contentResolver;
}
public String getConfig(String key) throws NoSuchFieldException {
String value = null;
Cursor cursor = getContentResolver().query(...);
if (cursor.moveToFirst()) {
//...
}
//..
}
}
Run Code Online (Sandbox Code Playgroud)
Jen*_*ten 18
下面是一个示例测试,它使用getContentResolver().query从内容提供程序返回模拟数据.
它应该适用于任何内容提供商,只需进行一些修改,但此示例模拟从联系人内容提供商返回电话号码
因为查询是最终方法,所以您不仅需要模拟MockContentProvider,还需要模拟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));
}
}
}
Run Code Online (Sandbox Code Playgroud)
如果你想让getContext()在被测试的类中返回而不是传入它,你应该能够在你的android测试中覆盖getContext(),就像这样
@Override
public Context getContext(){
return new ContextWithMockContentResolver(super.getContext());
}
Run Code Online (Sandbox Code Playgroud)
这个问题已经很老了,但人们可能仍然像我一样面临这个问题,因为没有很多关于测试的文档。
对我来说,对于依赖于内容提供者(来自 android API)的测试类,我使用了 ProviderTestCase2
public class ContactsUtilityTest extends ProviderTestCase2<OneQueryMockContentProvider> {
private ContactsUtility contactsUtility;
public ContactsUtilityTest() {
super(OneQueryMockContentProvider.class, ContactsContract.AUTHORITY);
}
@Override
protected void setUp() throws Exception {
super.setUp();
this.contactsUtility = new ContactsUtility(this.getMockContext());
}
public void testsmt() {
String phoneNumber = "777777777";
String[] exampleData = {phoneNumber};
String[] examleProjection = new String[]{ContactsContract.PhoneLookup.NUMBER};
MatrixCursor matrixCursor = new MatrixCursor(examleProjection);
matrixCursor.addRow(exampleData);
this.getProvider().addQueryResult(matrixCursor);
boolean result = this.contactsUtility.contactBookContainsContact(phoneNumber);
// internally class under test use this.context.getContentResolver().query(); URI is ContactsContract.PhoneLookup.CONTENT_FILTER_URI
assertTrue(result);
}
}
public class OneQueryMockContentProvider extends MockContentProvider {
private Cursor queryResult;
public void addQueryResult(Cursor expectedResult) {
this.queryResult = expectedResult;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
return this.queryResult;
}
}
Run Code Online (Sandbox Code Playgroud)
它是使用 Jenn Weingarten 的答案编写的。需要注意的几件事:MockContentProvider- 你必须是公开的 - 你必须使用Contextfrom 方法this.getMockContext()而不是this.getContext()在你的被测类中,否则你将访问的不是模拟数据而是来自设备的真实数据(在这种情况下 - 联系人) - 测试不能与AndroidJUnit4 运行程序 - 测试当然必须作为 android 插装测试运行 - 测试(权限)的构造函数中的第二个参数必须与被测类中查询的 URI 相同 - 模拟提供程序的类型必须作为类参数提供
基本上 ProviderTestCase2 使您可以初始化模拟上下文、模拟内容解析器和模拟内容提供者。
我发现使用旧的测试方法更容易,而不是尝试使用 mockito 和 junit4 为高度依赖于 android api 的类编写本地单元测试。
| 归档时间: |
|
| 查看次数: |
9702 次 |
| 最近记录: |