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

发布于 2024-07-30 07:42:04 字数 359 浏览 4 评论 0原文

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

您如何测试您的内容提供商?

谢谢

I am trying to test my DB using ProviderTestCase2<T>. I can see the test DB being created. As such I suppose, the tested content provider should use the test DB. But as soon as I try any calls against the MockContentResolver (or the one created with newResolverWithContentProviderFromSql), I get an UnsupportedOperationException. This is documented for the MockContentResolver as normal behavior. As such I am a bit unsure on the purpose of the ProviderTestCase2.

How do you test your content providers?

Thanks

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

孤单情人 2024-08-06 07:42:04

据我发现,设置模拟内容解析器并不是明确必要的 - 我可能会监督它的情况(也许通过 URI 正确解析提供者,需要正确的 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);
        }
    }
}

As far as I found, setting up the mock content resolver is not explicitly necessary - I might oversee cases where it is(maybe correct resolving of the provider via URI, hings that need corect getType() working), but for me, it was enough to do something like this:

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);
        }
    }
}
夏末染殇 2024-08-06 07:42:04

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

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

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

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

然后,不要直接使用您的提供程序(避免使用 getProvider() 因为您的内容提供程序的用户赢得了不能直接访问),使用 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);
}

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

I add this entry as I think it can help programmers that want to test their Content Provider.

Imagine your Content Provider is called MyProvider and that you have a contract class called MyProviderContract defining some constants.

First of all, you'll write a test class called MyProviderTestCase that inherits from ProviderTestCase2<MyProvider>. You'll have to define a constructor which will call the super constructor:

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

Then, instead of using directly your provider (avoid using getProvider() as users of your content provider won't access it directly), use the getMockContentResolver() to obtain a reference to a content resolver and then call the methods of this content resolver (query, insert, etc.). In the following code, I show how to test the insert method.

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);
}

Then you can add as many test methods as you want, using a content resolver instead of your content provider directly, as would do users of your content provider.

相思故 2024-08-06 07:42:04

[与问题没有直接关系,但供任何来到这里寻找如何在 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

}

然后,您可以在测试用例

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
}

}

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

[not directly related to question, but for future reference for whoever gets here looking for how to test content providers in android]

If working with API 28 or above, ProviderTestCase2 was removed from default classpath in Android SDK, so you need to manually add back in those classes in your build.gradle file.

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

}

Then you can just extend ProviderTestCase2 in your test case

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
}

}

working example: https://github.com/Artenes/android-content-provider-test-sample

水波映月 2024-08-06 07:42:04

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

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

MyMockContentResolver 将需要重写您想要在 ContentProvider 中测试的任何方法。

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

Extend ProviderTestCase2 to override getMockContentResolver() and return your own class derived from MockContentResolver.

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

MyMockContentResolver will need to override any methods you want to test in your ContentProvider.

Then you should be able to run any tests you want on your content provider while it's isolated by ProviderTestCase2

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文