简体   繁体   English

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

[英]How to test content providers on Android

I am trying to test my DB using ProviderTestCase2<T> .我正在尝试使用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 .但是,一旦我尝试对MockContentResolver (或使用newResolverWithContentProviderFromSql创建的调用)进行任何调用,我就会收到UnsupportedOperationException This is documented for the MockContentResolver as normal behavior.这被 MockContentResolver 记录为正常行为。 As such I am a bit unsure on the purpose of the ProviderTestCase2.因此,我对 ProviderTestCase2 的目的有点不确定。

How do you test your content providers?你如何测试你的内容提供者?

Thanks谢谢

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:据我发现,设置模拟内容解析器不是明确必要的 - 我可能会监督它所在的情况(可能通过 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);
        }
    }
}

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.假设您的 Content Provider 名为 MyProvider,并且您有一个名为 MyProviderContract 的合同类定义了一些常量。

First of all, you'll write a test class called MyProviderTestCase that inherits from ProviderTestCase2<MyProvider> .首先,您将编写一个名为MyProviderTestCase的测试类,它继承自ProviderTestCase2<MyProvider> You'll have to define a constructor which will call the super constructor:您必须定义一个构造函数来调用super构造函数:

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.).然后,不要直接使用您的提供者(避免使用getProvider()因为您的内容提供者的用户不会直接访问它), getMockContentResolver()使用getMockContentResolver()获取对内容解析器的引用,然后调用此内容解析器的方法( queryinsert等)。 In the following code, I show how to test the insert method.在下面的代码中,我展示了如何测试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);
}

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

Extend ProviderTestCase2 to override getMockContentResolver() and return your own class derived from MockContentResolver.扩展 ProviderTestCase2 以覆盖 getMockContentResolver() 并返回您自己的从 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. MyMockContentResolver 将需要覆盖您要在 ContentProvider 中测试的任何方法。

Then you should be able to run any tests you want on your content provider while it's isolated by ProviderTestCase2然后你应该能够在你的内容提供者上运行你想要的任何测试,同时它被 ProviderTestCase2 隔离

[not directly related to question, but for future reference for whoever gets here looking for how to test content providers in android] [与问题没有直接关系,但供将来寻找如何在 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.如果使用 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

}

Then you can just extend ProviderTestCase2 in your test case然后你可以在你的测试用例中扩展 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
}

}

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

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

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