matthewtyler.io

Testing Content Providers: Android Programming

September 06, 2012

Content Providers are a means of encapsulating and providing data to applications through a simple interface. Content Providers are therefore one of the main building blocks in android applications along with services and activities.

Now, you can quite easily embed raw sql queries and data access methods directly into your activity, but it is cleaner and better practice to have some separate interface that you can use isolate and test data access methods. The Content Provider is also required if you want to expose data in your application to third-party applications. Imagine you wanted to implemented a widget that uses the data from your application; it would require you to define a Content Provider to do so.

In order to define a Content Provider, you must implement the following methods;

delete(Uri, String, String[]) which deletes data from the content provider

getType(Uri) which returns the MIME type of data in the content provider

It is important to note, that the primary mechanism by which we are making queries is through the Uri. Every Content Provider defines an authority (usually the package name with that of Content Provider appended to it ie: com.example.myapp.MyContentProvider) which is declared in your applications manifest file, within the application tag, like thus;

The next step in building a Content Provider is to identify what data needs to be queried. For the sake of brevity, we will implement a content provider that will can query the asana api to return a list of workspaces, and a list of projects in a particular workspace. This link contains the asana api documentation http://developer.asana.com/documentation/.

From this documentation, we can see that the two http requests that need to be made are;

For actually making the requests, I will use the aquery library for simplicity, which can be found here - http://code.google.com/p/android-query/
- though you should be able to follow along without knowledge of this library.

Content Providers function by being passed a Uri which determines what data it should query. You then need to determine a sensible set of Uri’s for determining what data to fetch.

Usually, the uri should be of the format ‘content:///tablename’ so in our example, we will define our two uri’s as

content://com.example.myapp/workspaces

and

content://com.example/myapp/projects/workspaces/x where x is the id of the workspace

Note that I’ve rearranged the uri a little as compared with the http request. The URI object libraries in the android/java api have helper functions that make it easy to strip the last path segment.

Now onto the actual content provider code!

We first define a Uri matcher class within the ContentProvider Class ie;

The switch statement will check what uri we have received, and then use it to build the corresponding uri request. The rest of the code is just making the http request and parsing the JSON response into a matrixcursor. Note that you must return a cursor; The easiest way to do this is by using MatrixCursor, which you construct by passing a String array which contains a list of column names to the constructor.

That’s basically it.

To access the data in your activity, service etc can be done in a few different manners

Use a loader - which will involved creating a CursorLoader which can query the Uri directly, load everything in another thread, and keep everything all nice and organised (this is probably the best way)

Calling getContentResolver() in your activity and using the ContentResolver to directly query the ContentProvider - note that if your content provider is synchronous it will block the main thread, so make sure the call is asynchronous if you are going to do this. In my example, I’ve made a synchronous call.

Android Design Patterns recommend using loaders.

Now lets say we want to make some tests for content provider, to check that we’ve done everything properly. Androids test framework (based on junit) allows you to do this with the ProviderTestCase2 class, which will set up the MockContentResolver object that will allow us to test our Content Provider.

Using ProviderTestCase2 we request a MockContentResolver object and use this to make queries to the content provider. The setup() and tearDown() methods execute before each test and are used to perform initialisation. You can then define as many test cases as you like and use assertions to check that you are retrieving the correct data from the Content Provider.