【问题标题】:How to set up Android's MockContentProvider如何设置 Android Mock ContentProvider
【发布时间】:2012-09-27 07:59:11
【问题描述】:

我目前正在测试 Android 的 ContentProvider,但在模拟它时遇到了一些问题。我已经在网上花了几天时间,但除了Android Developer Site上的介绍外,没有找到任何有用的例子。

我实现了一个 ContentProvider 并编写了一些测试。一切都在这里工作得很好。测试结果符合我的预期。

public class DirectMessageProviderTest extends ProviderTestCase2<DirectMessageProvider>{

    @SmallTest
    public void testInsert() {
        Log.d(TAG, "testInsert");

        /*
         * result retrieves twitterId for the newly inserted item
         */
        Uri result = provider.insert(
                DirectMessageProvider.CONTENT_URI, 
                createContentValues());

        Log.i(TAG, "INSERT; id for newly inserted item: " + result);

        assertNotNull("INSERT!!! failed", result);

        if (result != null) {
            isDirectMessageInserted = true;
        }
    }

    @SmallTest
    public void testQuery() {
        Log.d(TAG, "testQuery");

        Uri uri = Uri.withAppendedPath(
                DirectMessageProvider.CONTENT_URI, 
                String.valueOf(directMessage.getTwitterId()));

        /*
         * result retrieves a cursor or null
         */
        Cursor result = provider.query(
                uri, 
                null, 
                null, 
                null, 
                null);

        Log.i(TAG, "QUERY; number of rows inside the cursor: " + result.getCount());

        int expected = isDirectMessageInserted ? 1 : 0;

        assertEquals("QUERY!!! failed", expected, result.getCount());
    }
}

我还实现了一个封装 ContentProvider 的类,并提供比删除、插入、查询和更新更复杂的方法。看看吧!

public class DirectMessageDataAccessImpl implements
        DirectMessageDataAccessInterface {

    @Override
    public boolean isStored(TwitterDirectMessage directMessage)
            throws DataAccessException {
        Log.d(TAG, "isStored");

        try {
            Uri uri = Uri.withAppendedPath(
                    DirectMessageProvider.CONTENT_URI, 
                    String.valueOf(directMessage.getTwitterId()));

            Cursor cursor = resolver.query(
                    uri, 
                    null, 
                    null, 
                    null, 
                    null);

            cursor.moveToFirst();

            boolean result = (cursor.getCount() > 0 ? true: false);

            cursor.close();

            return result;
        } catch (Exception e) {
            Log.e(TAG, e.getMessage(), e);
            throw new DataAccessException(e.getMessage());
        }
    }
}

最后我们来解决我为这个类编写测试的问题。我想使用模拟的 ContentResolver 为这个类编写独立的测试。我找到了这个 [example] (http://www.androidadb.com/source/npr-android-app-read-only/Npr_Test/src/org/npr/android/util/PlaylistProviderTest.java.html)上网并尝试使用 MockContentResolver。

首先,我创建了一个新的 ContentProvider,它将从测试类中检索删除、插入、查询和更新调用,以一次又一次地创建相同的答案。

public class DirectMessageDataAccessTest extends ProviderTestCase2<DirectMessageProvider>{

    private ContentProvider provider = new ContentProvider() {

        @Override
        public int update(Uri uri, ContentValues values, String selection,
                String[] selectionArgs) {
            Log.d(TAG, "update");
            return 0;
        }

        @Override
        public Cursor query(Uri uri, String[] projection, String selection,
                String[] selectionArgs, String sortOrder) {
            Log.w(TAG, "query");
            return null;
        }

        @Override
        public boolean onCreate() {
            Log.d(TAG, "onCreate");
            return false;
        }

        @Override
        public Uri insert(Uri uri, ContentValues values) {
            Log.d(TAG, "insert");
            return null;
        }

        @Override
        public String getType(Uri uri) {
            Log.d(TAG, "getType");
            return null;
        }

        @Override
        public int delete(Uri uri, String selection, String[] selectionArgs) {
            Log.d(TAG, "delete");
            return 0;
        }
    };
}

在此之后,我修改了我的 setUp 方法以创建一个 MockContentResolver 并在上面添加了我的 ContentProvider

@Override
protected void setUp() throws Exception {
    super.setUp();

    /*
     * MockContentResolver overrides Android's normal way of resolving providers by authority
     */
    MockContentResolver resolver = new MockContentResolver();

    /*
     * Adds access to a provider based on its authority
     */
    resolver.addProvider(DirectMessageProvider.AUTHORITY, provider);        

    context = new IsolatedContext(resolver, getContext());

    this.setContext(context);
}

最后但同样重要的是,我为我的 isStored 方法编写了一个测试用例。

public void testIsStored() {
    Log.d(TAG, "testIsStored");

    TwitterDirectMessage directMessage = new TwitterDirectMessage();

    directMessage.setTwitterId(123456);

    DirectMessageDataAccessInterface dataAccess = 
            new DirectMessageDataAccessImpl(context);

    try {
        assertFalse(dataAccess.isStored(directMessage));
    } catch (DataAccessException e) {
        e.printStackTrace();
        fail("...");
    }
}

不幸的是,android.content.ContentProvider 总是抛出 NullPointerException。我在 DirectMessageDataAccessImpl 的第 72 行调用resolver.query(...)

E/DirectMessageDataAccessImpl(1758): null
E/DirectMessageDataAccessImpl(1758): java.lang.NullPointerException
E/DirectMessageDataAccessImpl(1758):    at android.content.ContentProvider$Transport.enforceReadPermission(ContentProvider.java:284)
E/DirectMessageDataAccessImpl(1758):    at android.content.ContentProvider$Transport.query(ContentProvider.java:177)
E/DirectMessageDataAccessImpl(1758):    at android.content.ContentResolver.query(ContentResolver.java:311)
E/DirectMessageDataAccessImpl(1758):    at xxx.xxxxx.xxxxxxx.app.database.dataaccess.implementation.DirectMessageDataAccessImpl.isStored(DirectMessageDataAccessImpl.java:72)
E/DirectMessageDataAccessImpl(1758):    at xxx.xxxxx.xxxxxxx.app.test.dataaccess.DirectMessageDataAccessTest.testIsStored(DirectMessageDataAccessTest.java:107)

【问题讨论】:

    标签: android android-contentresolver android-testing


    【解决方案1】:

    在构造函数中你应该设置

    public YourClass() {
        super(DBProvider.class, "com.yourpackage.main");// class of Your Content provider and application package
    }
    

    然后调用

    MockContentResolver mockContentResolver = getMockContentResolver();
    assertNotNull(mockContentResolver);
    

    在测试中

    【讨论】:

    • 有什么方法可以注入我自己的提供程序以获得静态结果?一旦我添加了“addProvider”,我就会得到上面的 NullPointerException。
    • 你在这里添加你自己的提供者 -> super(DBProvider.class, "com.yourpackage.main"); MockContentResolver 将继续引用您的提供者
    猜你喜欢
    • 1970-01-01
    • 2011-07-13
    • 2011-01-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多