繁体   English   中英

如何在 Android 上测试内容提供程序

[英]How to test content providers on Android

我正在尝试使用ProviderTestCase2<T>测试我的数据库。 我可以看到正在创建的测试数据库。 因此,我想,经过测试的内容提供者应该使用测试数据库。 但是,一旦我尝试对MockContentResolver (或使用newResolverWithContentProviderFromSql创建的调用)进行任何调用,我就会收到UnsupportedOperationException 这被 MockContentResolver 记录为正常行为。 因此,我对 ProviderTestCase2 的目的有点不确定。

你如何测试你的内容提供者?

谢谢

据我发现,设置模拟内容解析器不是明确必要的 - 我可能会监督它所在的情况(可能通过 URI 正确解析提供者,需要 corect getType() 工作的铰链),但对我来说,它是足以做这样的事情:

package org.droidcon.apps.template.provider.test;

import org.droidcon.apps.template.provider.ProfileContract;
import org.droidcon.apps.template.provider.ProfileProvider;

import android.content.ContentProvider;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
import android.test.ProviderTestCase2;

public class ProfileProviderTest extends ProviderTestCase2<ProfileProvider> {

    public ProfileProviderTest() {
        super(ProfileProvider.class, ProfileProvider.class.getName());
    }

    protected void setUp() throws Exception {
        super.setUp();
    }


    /**
     * Very basic query test.
     * 
     * Prerequisites: 
     * <ul>
     * <li>A provider set up by the test framework
     * </ul>
     * 
     * Expectations: 
     * <ul>
     * <li> a simple query without any parameters, before any inserts returns a 
     * non-null cursor
     * <li> a wrong uri results in {@link IllegalArgumentException}
     * </ul>
     */
    public void testQuery(){
        ContentProvider provider = getProvider();

        Uri uri = ProfileContract.CONTENT_URI;

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

        assertNotNull(cursor);

        cursor = null;
        try {
            cursor = provider.query(Uri.parse("definitelywrong"), null, null, null, null);
            // we're wrong if we get until here!
            fail();
        } catch (IllegalArgumentException e) {
            assertTrue(true);
        }
    }
}

我添加此条目是因为我认为它可以帮助想要测试其内容提供程序的程序员。

假设您的 Content Provider 名为 MyProvider,并且您有一个名为 MyProviderContract 的合同类定义了一些常量。

首先,您将编写一个名为MyProviderTestCase的测试类,它继承自ProviderTestCase2<MyProvider> 您必须定义一个构造函数来调用super构造函数:

public MyProviderTestCase() {
    super(MyProvider.class, MyProviderContract.AUTHORITY);
}

然后,不要直接使用您的提供者(避免使用getProvider()因为您的内容提供者的用户不会直接访问它), getMockContentResolver()使用getMockContentResolver()获取对内容解析器的引用,然后调用此内容解析器的方法( queryinsert等)。 在下面的代码中,我展示了如何测试insert方法。

public void testInsert() {
    Uri uri = MyProviderContract.CONTENT_URI;
    ContentValues values = new ContentValues();
    values.put(MyProviderContract.FIELD1, "value 1");
    values.put(MyProviderContract.FIELD2, "value 2");
    Uri resultingUri = getMockContentResolver().insert(uri, values);
    // Then you can test the correct execution of your insert:
    assertNotNull(resultingUri);
    long id = ContentUris.parseId(resultingUri);
    assertTrue(id > 0);
}

然后,您可以根据需要添加任意数量的测试方法,直接使用内容解析器而不是内容提供者,就像内容提供者的用户一样。

扩展 ProviderTestCase2 以覆盖 getMockContentResolver() 并返回您自己的从 MockContentResolver 派生的类。

public class MyProviderTestCase2 extends ProviderTestCase2 {
    @Override
    public MockContentResolver getMockContentResolver () {
        return new MyMockContentResolver();
    }
}

MyMockContentResolver 将需要覆盖您要在 ContentProvider 中测试的任何方法。

然后你应该能够在你的内容提供者上运行你想要的任何测试,同时它被 ProviderTestCase2 隔离

[与问题没有直接关系,但供将来寻找如何在 android 中测试内容提供者的人参考]

如果使用 API 28 或更高版本,ProviderTestCase2 已从 Android SDK 的默认类路径中删除,因此您需要在 build.gradle 文件中手动添加回这些类。

android {

  //libraries added to classpath with useLibrary are being get from Sdk/platforms/android-XX/optional

  //adds ProviderTestCase2 to classpath from android.test package that comes with android SDK
  useLibrary 'android.test.runner'

  //adds AndroidTestCase to classpath from android.test package that comes with android SDK
  useLibrary 'android.test.base'

  //adds MockContentProvider to classpath from android.test.mock package that comes with android SDK
  useLibrary 'android.test.mock'

  //if you compiling against 27 or lower you do not need to add useLibrary calls above
  //only from api 28 above those classes were removed from the default classpath
  compileSdkVersion 30

}

然后你可以在你的测试用例中扩展 ProviderTestCase2

package com.example.samplecontentprovidertest;

import android.test.ProviderTestCase2;

public class ExampleContentProviderTest extends ProviderTestCase2<ExampleContentProvider> {

public ExampleContentProviderTest() {
    super(ExampleContentProvider.class, ExampleContentProvider.AUTHORITY);
}

public void testUpdate() {
    int affectedRows = getMockContentResolver().update(ExampleContentProvider.SAMPLE_URI, null, null, null);
   //validate update
}

public void testDelete() {
    int affectedRows = getMockContentResolver().delete(ExampleContentProvider.SAMPLE_URI, null, null);
    //validate insert
}

}

工作示例:https ://github.com/Artenes/android-content-provider-test-sample

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM