Room Database with Content Provider in Java-Part2

Rashmi Rangaswamaiah
4 min readJan 3, 2021

As we have already seen the implementation in the previous article on how to use ROOM to query the database and expose the data to other applications. Now it’s time to test our implementation and this can be done with the instrumented test. In this article, we will write a simple test class.

Firstly, we need to configure the gradle file specifying the runner. AndroidJunitRunner is the instrumentation runner. This is mainly the entry point for running our entire suite of tests. It controls the test apk, test environment and executes all of the tests that are defined in our test package.

build.gradle(:app)

android {
defaultConfig{
testInstrumentationRunner “androidx.test.runner.AndroidJUnitRunner”
}
}

Next, we annotate our test class with AndroidJunit4. AndroidJUnit4 is the class test runner. This will drive the tests for a single class. If we are creating an instrumented JUnit 4 test class to run on a device or emulator, the test class must be prefixed with the @RunWith(AndroidJUnit4.class) annotation.

@RunWith(AndroidJUnit4.class)
public class PersonContentProviderTest { ... }

Let’s initialize the database in the public void method with Before annotation, by creating an in-memory instance of our Room database. In the case of an in-memory database, any data that has been added is lost when the process is killed. Here we pass the reference to the context and the database class to be used for the builder.

@Before
public void setUp() {
Room.inMemoryDatabaseBuilder(InstrumentationRegistry.getInstrumentation().getContext(),
ApplicationDatabase.class).allowMainThreadQueries().build();
}

Let’s see how our class look like:

@RunWith(AndroidJUnit4.class)
public class PersonContentProviderTest {
private static final String TAG = PersonContentProviderTest.class.getName();private static final Uri PERSON_URI = Uri.parse("content://" + AUTHORITY + "/" + PERSON_TABLE_NAME);private static final Uri PERSON_URI_ID = Uri.parse("content://" + AUTHORITY + "/" + PERSON_TABLE_NAME + "/" + "1");private ContentResolver contentResolver;@Before
public void setUp() {
Room.inMemoryDatabaseBuilder(InstrumentationRegistry.getInstrumentation().getContext(),
ApplicationDatabase.class).allowMainThreadQueries().build();
contentResolver = InstrumentationRegistry.getInstrumentation().getContext().getContentResolver();
}
@Test
public void insertPersonData() {
Uri insertUri = contentResolver.insert(PERSON_URI, contentValues());
assertNotNull(insertUri);
}
@Test
public void queryPerson() {
Cursor cursor = contentResolver.query(PERSON_URI, null, null,
null, null);
assertNotNull(cursor);
if (cursor.moveToFirst()) {
do {
String name = cursor.getString(cursor.getColumnIndex(PERSON_NAME));
String gender = cursor.getString(cursor.getColumnIndex(PERSON_GENDER));
String emailAddress = cursor.getString(cursor.getColumnIndex(PERSON_EMAIL_ADDRESS));
}
while (cursor.moveToNext());
}
cursor.close();
}
@Test
public void personDelete() {
Uri itemUri = contentResolver.insert(PERSON_URI, getContentValues());
assertNotNull(itemUri);
Cursor cursor = contentResolver.query(PERSON_URI, new String[]{PERSON_NAME}, null,
null, null);
assertNotNull(cursor);
cursor.close();
int count = contentResolver.delete(itemUri, null, null);
assertNotNull(count);
}
@Test
public void delete() {
int count = contentResolver.delete(PERSON_URI_ID, null, null);
assertNotNull(count);
}
private ContentValues contentValues() {
ContentValues contentValues = new ContentValues();
contentValues.put(PERSON_NAME, "Rashmi");
contentValues.put(PERSON_GENDER, "female");
contentValues.put(PERSON_EMAIL_ADDRESS, "123@gmail.com");
return contentValues;
}
}

As you can see in the above code, we use the ContentResolver object if we want to access data in a content provider. The ContentResolver communicates with the provider object, the provider object receives data requests from clients, performs requested action, and returns the results. The ContentResolver includes the CRUD methods corresponding to the abstract methods in the Content Provider class.

ContentResolver doesn’t know the implementation of the provider that is interacting with, each method is passed a URI that specifies the Content Provider to interact with. The ContentResolver selects the right Content Provider based on the ContentUri. This is a URI that identifies data in a provider. It includes the name of the entire provider (authority) and a name that points to a table (path). ContentUri looks like this:

content://com.example.democontentprovider.provider/person_info
  • content://: Is the scheme that is always present and identifies this as a content URI
  • com.example.democontentprovider.provider: Is the provider’s authority
  • person_info: Is the table’s path (eg: table name)

Please look into the diagram that is shown in the Part1 for better understanding.

Now it’s time to understand each of the methods in detail:

Before that, I would like to mention that the method that is defined as a test method needs to be annotated with the @Test annotation.

query()

@Test
public void queryPerson() {
Cursor cursor = contentResolver.query(PERSON_URI, null, null, null, null);
}
  • The query() method belongs to ContentResolver class, it invokes the abstract query() method of resolved ContentProvider.
  • When the query method is invoked, the Content Resolver parses the URI argument and extracts its authority.
  • Then the request is directed to the content provider registered with the authority. This is performed by invoking the Content Provider’s query method.
  • The Content Provider’s query is performed and a Cursor is returned (an exception is thrown if not).

insert()

@Test
public void insertPersonData() {
Uri insertUri = contentResolver.insert(PERSON_URI, getContentValues());
}
  • The insert() method belongs to the ContentResolver class, which invokes the abstract insert() method of the ContentProvider.
  • We pass the uri argument and the ContentValues. The ContentValues contains the data that will be inserted into the table at the given URL. The ContentValues is a map like a class that matches a value to a string key. Look at the snippet below:
private ContentValues contentValues() {
ContentValues contentValues = new ContentValues();
contentValues.put(PERSON_NAME, "Rashmi");
contentValues.put(PERSON_GENDER, "female");
contentValues.put(PERSON_EMAIL_ADDRESS, "123@gmail.com");
return contentValues;
}

delete()

@Test
public void delete() {
int count = contentResolver.delete(PERSON_URI_ID, null, null);
}
  • The delete() method belongs to the ContentResolver class, it invokes the abstract delete() method of the ContentProvider.
  • Here, we see pass an argument PERSON_ URI_ ID. This deletes by ID. In the constant of the PERSON_ URI_ ID we specify as 1, this means it deletes the row with id 1 from the table person_info.

This is the simplest way to test the content provider. I hope that my articles gave you some insight about exposing the data to another application through a content provider and how to test it.

--

--

Rashmi Rangaswamaiah

Developer | Traveller | Excited Learner | Indian | Kannadiga | Bengaluru-Germany-Belgium |