Fix unit tests to work with a singleton DBHelper instance.

The fix for the database locking bug was to have a singleton
`DBHelper` instance. This breaks tests because multiple tests
share the same database. The solution is to:

 * Hack together a static method which clears the singleton,
   then invoke it in the `setUp()` method for relevant test cases.

 * Ensure the mock context provided to the providers during
   the tests is able to provide a context via `getApplicationContext()`.
   Without this, the mock context throws an `UnsupportedOperationException`
   when invoking this method.
This commit is contained in:
Peter Serwylo 2016-01-26 08:49:23 +11:00
parent f7bbf0e282
commit 97cc279d99
5 changed files with 30 additions and 3 deletions

View File

@ -72,6 +72,13 @@ public abstract class FDroidProvider extends ContentProvider {
return result;
}
/**
* Only used for testing. Not quite sure how to mock a singleton variable like this.
*/
public static void clearDbHelperSingleton() {
dbHelper = null;
}
private static synchronized DBHelper getOrCreateDb(Context context) {
if (dbHelper == null) {
Utils.debugLog(TAG, "First time accessing database, creating new helper");

View File

@ -20,6 +20,7 @@ import android.annotation.TargetApi;
import android.content.ContentProvider;
import android.content.ContentResolver;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.res.Resources;
import android.database.DatabaseUtils;
import android.os.Build;
@ -136,12 +137,20 @@ public abstract class ProviderTestCase2MockContext<T extends ContentProvider> ex
mResolver = new MockContentResolver();
final String filenamePrefix = "test.";
RenamingDelegatingContext targetContextWrapper = new
final RenamingDelegatingContext targetContextWrapper = new
RenamingDelegatingContext(
createMockContext(new MockContext2()), // The context that most methods are delegated to
getContext(), // The context that file methods are delegated to
filenamePrefix);
mProviderContext = new IsolatedContext(mResolver, targetContextWrapper);
mProviderContext = new IsolatedContext(mResolver, new ContextWrapper(targetContextWrapper) {
// The FDroidProvider class needs access to an application context in order to initialize
// the singleton DBHelper instance.
@Override
public Context getApplicationContext() {
return targetContextWrapper;
}
});
mProvider = mProviderClass.newInstance();
mProvider.attachInfo(mProviderContext, null);

View File

@ -1,5 +1,6 @@
package mock;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.test.mock.MockContentResolver;
@ -8,7 +9,6 @@ import android.test.mock.MockContext;
public class MockContextSwappableComponents extends MockContext {
private PackageManager packageManager;
private Resources resources;
private MockContentResolver contentResolver;

View File

@ -45,6 +45,8 @@ public abstract class FDroidProviderTest<T extends FDroidProvider> extends Provi
public void setUp() throws Exception {
super.setUp();
FDroidProvider.clearDbHelperSingleton();
// Instantiate all providers other than the one which was already created by the base class.
// This is because F-Droid providers tend to perform joins onto tables managed by other
// providers, and so we need to be able to insert into those other providers for these

View File

@ -18,6 +18,7 @@ import org.fdroid.fdroid.RepoUpdater.UpdateException;
import org.fdroid.fdroid.data.Apk;
import org.fdroid.fdroid.data.ApkProvider;
import org.fdroid.fdroid.data.AppProvider;
import org.fdroid.fdroid.data.FDroidProvider;
import org.fdroid.fdroid.data.Repo;
import org.fdroid.fdroid.data.RepoProvider;
import org.fdroid.fdroid.data.TempApkProvider;
@ -122,12 +123,20 @@ public class MultiRepoUpdaterTest extends InstrumentationTestCase {
public File getDatabasePath(String name) {
return new File(getInstrumentation().getContext().getFilesDir(), "fdroid_test.db");
}
@Override
public Context getApplicationContext() {
// Used by the DBHelper singleton instance.
return this;
}
}
@Override
public void setUp() throws Exception {
super.setUp();
FDroidProvider.clearDbHelperSingleton();
context = new TestContext();
testFilesDir = TestUtils.getWriteableDir(getInstrumentation());