Using RenamingDelegatingContext to mock ContentResolver in Android

Mocking Context

Testing in Android can be complex, especially when your component is not isolated from the Android framework. One example of this is when your component is performing file system tasks using Context. E.g, the Activity class has the following methods (inherited from Context):

When calling any of the methods above, Context directs the calls to parts of the file system dedicated to your specific application, usually located under /data/data/<your.applications.package.name>/. To mock away these type of operations, there is a component called RenamingDelegatingContext. It basically allows you to replace the context used when calling file system methods, re-directing the call to a mocked data file instead of the real file. The source code for RenamingDelegatingContext can be looked at here:

RenamingDelegatingContext

There are a number of tutorials on how to use RenamingDelegatingContext to mock away your files or databases;

Advanced use of RenamingDelegatingContext

In addition to open resources directly using Context, one common task is to open a resoure using a ContentResolver:

The getContext() call can be omitted if you’re making the call from within an Activity or Service, where the component itself is a Context.

One might want the returned InputStream to point to a test resource instead of the real resource. This can be achieved with some research. When opening the InputStream, the ContentResolver finds the proper provider for the given authority (see ContentProvider section for more detail). The source code reveals more on how this is done:

ContentResolver.openInputStream

ContentResolver.openAssetFileDescriptor

As seen in the extracts above, the ContentResolver acquires the correct provider based on the given Uri (authority). In order for us to mock away this behavior, we need to do four things:

  1. Use a RenamingDelegatingContext to mock away the real Context (target Context) in the test.
  2. Override the getContentResolver in RenamingDelegatingContext to return a MockContentResolver.
  3. Create a ContentProvider to return a AssetFileDescriptor pointing to the test resource.
  4. Register the ContentProvider with the MockContentResolver to handle the authority we want to override.

Mocking ContentResolver

AssetManagerAndroidTestCase

Creating an example test

In the following example, the test_file.midi is a text file stored in the res/asset/ directory. The .midi extension is a workaround to prevent the Android Asset Packaging Tool (aapt) from compressing the file. If the file is compressed, it can only be opened as an InputStream and not as a FileDescriptor, which is needed for mocking away the ContentProvider. See this bug for more info.

That’s it!

Leave a Reply