Testing Android devices with ContentProviders

I am now afraid of a problem with unit testing on Android. My application uses Sqlite DB to store vehicle information. I recently added a ContentProvider template to retrieve data (to the database that you accessed directly).

The application works fine, but my tests sporadically fail to run in "run" mode on eclipse - they pass in "debug" mode. In my setUp () method, I create a RenamingDelegatingContext to create a test version of my database. All this is the prefix "test". to my database name to ensure that the "real" database is not affected by the test code. Then I pass this to the "data provider" class to save it as an instance variable until the first call to getWriteableDatabase () is called:

public class VehicleProviderTest extends InstrumentationTestCase { RenamingDelegatingContext renamingDelegatingContext; @Override protected void setUp() throws Exception { super.setUp(); if(null == renamingDelegatingContext) { renamingDelegatingContext = new RenamingDelegatingContext(getInstrumentation().getTargetContext(), "test."); } Log.d("UKMPG", "Initialising UKMPGDataProvider with test context: " + renamingDelegatingContext.getClass().toString()); MPGDataProvider.init(getTestContext(), Constants.DATABASE_NAME); deleteTestDatabase(); } } 

My ContentProvider onCreate () method does a similar job in that it also passes context to the data provider class:

  @Override public boolean onCreate() { Context context = getContext(); Log.d("UKMPG", "ContentProvider.onCreate called. Context: " + context.getClass().toString()); MPGDataProvider.init(getContext(), Constants.DATABASE_NAME); return true; } 

Now the problem; when I run my tests (again, this does not happen in debug mode), onCreate () in my ContentProvider is called after my setUp () method passed RenamingDelegatingContext to the data provider class, as a result of which it was overwritten. This means that a live database will be used for the tests (they will fail because the tests expect an empty database).

Here are a few logarithms showing correspondence with notes explaining what happens:

ContentProvider.onCreate calls and passes the context to UKMPGDataProvider:

 01-11 19:22:11.404: D/UKMPG(480): ContentProvider.onCreate called. Context: class android.app.Application 01-11 19:22:11.414: D/UKMPG(480): UKMPGDataProvider.init called. Context: class android.app.Application, db name :mpg_tracker.db 

Tests pass the RenamingDelegatingContext to UKMPGDataProvider:

 01-11 19:22:13.234: D/UKMPG(498): Initialising UKMPGDataProvider with test context: class android.test.RenamingDelegatingContext 01-11 19:22:13.234: D/UKMPG(498): UKMPGDataProvider.init called. Context: class android.test.RenamingDelegatingContext, db name :mpg_tracker.db 

ContentProvider.onCreate is called again (another PID) and passes the ApplicationContext to the UKMPGDataProvider, overwriting the RenamingDelegatingContext:

 01-11 19:22:13.254: D/UKMPG(498): ContentProvider.onCreate called. Context: class android.app.ApplicationContext 01-11 19:22:13.254: D/UKMPG(498): UKMPGDataProvider.init called. Context: class android.app.ApplicationContext, db name :mpg_tracker.db 

The first call to getWriteableDatabase () occurred, so the database will be created with the wrong context:

 01-11 19:22:13.265: D/UKMPG(498): database null - going to create it 

Another call to ContentProvider.onCreate has occurred! This time with a regular context. Damage has already been done, so it does not matter:

 01-11 19:22:13.265: D/UKMPG(498): ContentProvider.onCreate called. Context: class android.app.Application 

Creating a database with the wrong context:

 01-11 19:22:13.265: D/UKMPG(498): Creating DB instance with Context: class android.app.ApplicationContext 

init () called by the corresponding last call to ContentProvider.onCreate ():

 01-11 19:22:13.274: D/UKMPG(498): UKMPGDataProvider.init called. Context: class android.app.Application, db name :mpg_tracker.db 

getWriteableDatabase () returns a non-test database:

 01-11 19:22:13.374: D/UKMPG(498): getWritableDatabase. Path of returned db: /data/data/barry.contentproviderexample/databases/mpg_tracker.db 

Failed to delete the database for the next test because the database "test" does not exist:

 01-11 19:22:13.615: D/UKMPG(498): Database deleted:false 

For completeness, here is logcat from the same test when running in debug mode:

 01-11 19:37:09.514: D/UKMPG(598): ContentProvider.onCreate called. Context: class android.app.Application 01-11 19:37:09.514: D/UKMPG(598): UKMPGDataProvider.init called. Context: class android.app.Application, db name :mpg_tracker.db 01-11 19:37:11.313: D/UKMPG(616): ContentProvider.onCreate called. Context: class android.app.Application 01-11 19:37:11.313: D/UKMPG(616): UKMPGDataProvider.init called. Context: class android.app.Application, db name :mpg_tracker.db 

At this point, ContentProder.onCreate is called twice using a non-contextual context, but this happens before my setUp () method, so it does not affect the tests:

 01-11 19:37:14.173: D/UKMPG(616): Initialising UKMPGDataProvider with test context: class android.test.RenamingDelegatingContext 01-11 19:37:14.173: D/UKMPG(616): UKMPGDataProvider.init called. Context: class android.test.RenamingDelegatingContext, db name :mpg_tracker.db 01-11 19:37:14.213: D/UKMPG(616): database null - going to create it 01-11 19:37:14.213: D/UKMPG(616): Creating DB instance with Context: class android.test.RenamingDelegatingContext 01-11 19:37:14.364: D/UKMPG(616): getWritableDatabase. Path of returned db: /data/data/barry.contentproviderexample/databases/test.mpg_tracker.db 01-11 19:37:14.794: D/UKMPG(616): Database deleted:true 

Can someone help me figure this out? Am I doing something wrong, or is it an error (threading?) In Android?

It is repeated on devices and in versions from 1.6 to 4.0 for Android.

+4
android multithreading android-contentprovider unit-testing
source share
1 answer

I think you should call setContext () in your setUp ():

 // warning: untested code protected void setUp() throws Exception { super.setUp(); setContext(new RenamingDelegatingContext(getTargetContext(), "test."); ... } 

In this case, you may need to change the base class to ProviderTestCase2 .

+2
source share

All Articles