Android-ProviderTestCase2 with API Level 28 not working
Asked Answered
R

4

6

Some time ago I created some instrumented tests using ProviderTestCase2. Now I wanted to update my codebase and tried to reactivate my old tests in the current environment.

1) When I update to compileSdkVersion 28 there seems to be no class ProviderTestCase2 any more. Cleaning and building the Project failed. If I go back to version 27 I can successfully build the project.

2) I have a special case where I want to test different variants of an object with a set of tests. So I decided to make use of inheritance and placed the tests in the base class, configuring the objects to be tested by the superclass. This had worked in the past. (Yes, I know about opinions that inheritance in tests is bad, but in this case it is OK ;-) )

Now no tests are executed. Android Studio complains that there is an empty test suite.

Also there are warnings that I have tests with JUnit4 Annotations in a class extending JUnit3. I do not remember that I saw these warnings in the past.

Is this a bug in the Android Libraries? Or where can I find some hints how to solve this problem?

(Using Android Studio 3.2 and the currentmost libraries)

Regina answered 1/10, 2018 at 19:0 Comment(0)
S
5

The ProviderTestCase2 was removed. The ProviderTestRule should be used instead (from support test library or AndroidX).

See:

Add the com.android.support.test:rules dependency, to be able to use the rule.

Here is an example from the reference page:

@Rule
public ProviderTestRule mProviderRule =
    new ProviderTestRule.Builder(MyContentProvider.class, MyContentProvider.AUTHORITY).build();

@Test
public void verifyContentProviderContractWorks() {
    ContentResolver resolver = mProviderRule.getResolver();
    // perform some database (or other) operations
    Uri uri = resolver.insert(testUrl, testContentValues);
    // perform some assertions on the resulting URI
    assertNotNull(uri);
}
Saline answered 13/11, 2018 at 18:56 Comment(5)
Sorry for not updating this post timely. In the meantime I also had found this and was able to successfully migrate to the ProviderTestRule. So I will give you the credits for the solution ;-) But I did not found that the AndroidTestCase2 is now deprecated ... obviously it is, but nowhere mentioned. :-/Regina
Does someone know why the database is not cleared after each tests on API 28? I was using ProviderTestCase2 and it was working file (cleared the database after eache tests) until API27. I try to migrate to the ProviderTestRule to get it working on API28 but the database is still never cleared.Moira
@WebDucer, the fact the ProviderTestCase2 war removed from API 28, is this documented anywhere ? EDIT: I found the linkGhana
@mtotschnig's answer is correct. ProviderTestCase2 is not deprecated.Accouplement
Poor ProviderTestRule. It was beta for a long time, and now it is deprecated in androidx. We hardly knew ya. developer.android.com/reference/androidx/test/rule/provider/…Maestro
A
2

TLDR

build.gradle:

android {    
  useLibrary 'android.test.base' // for AndroidTestCase
  useLibrary 'android.test.runner' // for ProviderTestCase2
  useLibrary 'android.test.mock' // for MockContentProvider
}

Android documentation about various JUnit-based libraries available with the useLibrary call: https://developer.android.com/training/testing/set-up-project#junit-based-libs

Further Explanation

mtotschnig's answer is on the right track, but it isn't complete.

First, to import ProviderTestCase2, you need

build.gradle:

android {
  useLibrary 'android.test.runner'
}

However, ProviderTestCase2 extends AndroidTestCase, so you'll then need:

build.gradle:

android {
  useLibrary 'android.test.base'
}

Finally, if you're extending ProviderTestCase2, you need to provide a type extending ContentProvider, and you may need to extend MockContentProvider to create it. For MockContentProvider, you need (thanks to Sienna's related answer):

build.gradle:

android {
  useLibrary 'android.test.mock'
}
Accouplement answered 12/11, 2019 at 5:18 Comment(0)
A
1

The accepted answer is not correct. ProviderTestRule being in Beta, there is no deprecation or removal of ProviderTestCase2. What happened is that is has been moved to a library that you need to declare in your build.gradle:

useLibrary 'android.test.base'

See: https://developer.android.com/training/testing/set-up-project

Absolutism answered 9/11, 2019 at 7:51 Comment(0)
H
0

Tried ProviderTestRule many times to test my custom ContentProvider class but succeeded only when add my Test class to androidTest folder, here is the example kotlin code :

    //this is my custom provider class    
    public final class NameProvider : ContentProvider() {
        private var pContext: Context? = null;
        private var nameDbHelper: NameDbHelper? = null
        private var dataBase: SQLiteDatabase? = null
        private val Log_Tag = "NAME_PROVIDER"
        
        override fun onCreate(): Boolean {
            pContext = context
            nameDbHelper = pContext?.let { NameDbHelper(it) }
            dataBase = nameDbHelper?.writableDatabase
            if (dataBase == null) {
                Log.d(Log_Tag, "dataBase NOT created ...")
                return false
            }
            Log.d(Log_Tag, "dataBase created ...")
            return true
        }
    
        override fun query(p0: Uri, p1: Array<out String>?, p2: String?, p3: Array<out String>?, p4: String?): Cursor? {
            var queryBuilder : SQLiteQueryBuilder = SQLiteQueryBuilder()
            queryBuilder.tables = "TABLE_NAME"
            val cursor = queryBuilder.query(dataBase,p1,p2,p3,null,null, "COLUMN_NAME")
            cursor.setNotificationUri(pContext?.contentResolver, p0)
            return cursor
        }
    
        override fun insert(p0: Uri, p1: ContentValues?): Uri? {
            val rowID: Long? = dataBase?.insert("TABLE_NAME", "", p1)
            rowID?.let {
                if (it > 0) {
                    val _uri = ContentUris.withAppendedId(CONTENT_URI, it)
                    pContext?.contentResolver?.notifyChange(_uri, null)
                    return _uri
                }
            }
            throw SQLException("Failed to add a record into")
        }
        
        override fun getType(p0: Uri): String? {
            TODO("Not yet implemented")
        }
    
        override fun delete(p0: Uri, p1: String?, p2: Array<out String>?): Int {
            TODO("Not yet implemented")
        }
    
        override fun update(p0: Uri, p1: ContentValues?, p2: String?, p3: Array<out String>?): Int {
            TODO("Not yet implemented")
        }
    }

Now the test class that I can run successfully :

    @RunWith(AndroidJUnit4::class)
    class NameProviderTest {
        @get:Rule
        var mProviderRule = ProviderTestRule.Builder(NameProvider::class.java, NameContract.AUTHORITY)
                .setDatabaseCommands(NameContract.DATABASE_NAME).build()
    
        @Test
        fun contentResolverNull(){
            val resolver = mProviderRule.resolver
            assertNotNull(resolver)
        }

        @Test
        fun query() {
            val cursor = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                mProviderRule.resolver.query(NameContract.CONTENT_URI, null, null, null)
            } else {
                null
            }
            assertNotNull(cursor)
            var name : String? = null
            if(cursor != null && cursor.moveToFirst()){
                name = cursor.getString(cursor.getColumnIndex(NameContract.KEY_NAME))
            }
            assertNotNull(name)
            assertEquals(name, "Taher")
        }
    
        @Test
        fun insert() {
            val values =  ContentValues()
            values.put(NameContract.KEY_NAME, "Taher");
            val uri = mProviderRule.resolver.insert(NameContract.CONTENT_URI, values);
            assertNotNull(uri)
        }
    }

Better Approach

But then I have found a better way to do this by using robolectric:4.2 . This time it feels like actual unit test as I can do this by adding my Test class NameProviderTest to the test folder.

Now the test class look like this:

    @Config(maxSdk = 29)
    @RunWith(RobolectricTestRunner::class)
    class NameProviderTest {
    
        private var contentResolver : ContentResolver? = null
        private var shadowContentResolver : ShadowContentResolver? = null
        private var nameProvider : NameProvider? = null
        
        @Before
        fun setUp() {
            contentResolver = ApplicationProvider.getApplicationContext<Context>().contentResolver
            val providerInfo : ProviderInfo = ProviderInfo()
            providerInfo.authority = NameContract.AUTHORITY
            providerInfo.grantUriPermissions = true
            val controller = Robolectric.buildContentProvider(NameProvider::class.java).create(providerInfo)
            shadowContentResolver = shadowOf(contentResolver)
            nameProvider = controller.get()
    
        }
    
        @Test
        fun onCreate() {
            val res  = nameProvider?.onCreate()
            assertEquals(res, true)
            //ShadowContentResolver.registerProviderInternal(NameContract.AUTHORITY, nameProvider)
        }
    
        @Test
        fun query() {
            val values =  ContentValues()
            values.put(NameContract.KEY_NAME, "ABCD")
            val uri = contentResolver?.insert(NameContract.CONTENT_URI, values);
            assertNotNull(uri)
            val cursor = contentResolver?.query(NameContract.CONTENT_URI,null,null,null,null)
            assertNotNull(cursor)
            var name : String? = null
            if(cursor != null && cursor.moveToFirst()){
                name = cursor.getString(cursor.getColumnIndex(NameContract.KEY_NAME))
            }
            cursor?.close()
            assertNotNull(name)
            assertEquals(name, "ABCD")
        }
        
        @Test
        fun insert() {
            val values =  ContentValues()
            values.put(NameContract.KEY_NAME, "Taher")
            val uri = contentResolver?.insert(NameContract.CONTENT_URI, values);
            assertNotNull(uri)
    
        }
    
    }
Hypercritical answered 24/12, 2021 at 12:39 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.