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:
parent
f7bbf0e282
commit
97cc279d99
@ -72,6 +72,13 @@ public abstract class FDroidProvider extends ContentProvider {
|
|||||||
return result;
|
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) {
|
private static synchronized DBHelper getOrCreateDb(Context context) {
|
||||||
if (dbHelper == null) {
|
if (dbHelper == null) {
|
||||||
Utils.debugLog(TAG, "First time accessing database, creating new helper");
|
Utils.debugLog(TAG, "First time accessing database, creating new helper");
|
||||||
|
@ -20,6 +20,7 @@ import android.annotation.TargetApi;
|
|||||||
import android.content.ContentProvider;
|
import android.content.ContentProvider;
|
||||||
import android.content.ContentResolver;
|
import android.content.ContentResolver;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.content.ContextWrapper;
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
import android.database.DatabaseUtils;
|
import android.database.DatabaseUtils;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
@ -136,12 +137,20 @@ public abstract class ProviderTestCase2MockContext<T extends ContentProvider> ex
|
|||||||
|
|
||||||
mResolver = new MockContentResolver();
|
mResolver = new MockContentResolver();
|
||||||
final String filenamePrefix = "test.";
|
final String filenamePrefix = "test.";
|
||||||
RenamingDelegatingContext targetContextWrapper = new
|
final RenamingDelegatingContext targetContextWrapper = new
|
||||||
RenamingDelegatingContext(
|
RenamingDelegatingContext(
|
||||||
createMockContext(new MockContext2()), // The context that most methods are delegated to
|
createMockContext(new MockContext2()), // The context that most methods are delegated to
|
||||||
getContext(), // The context that file methods are delegated to
|
getContext(), // The context that file methods are delegated to
|
||||||
filenamePrefix);
|
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 = mProviderClass.newInstance();
|
||||||
mProvider.attachInfo(mProviderContext, null);
|
mProvider.attachInfo(mProviderContext, null);
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package mock;
|
package mock;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
import android.test.mock.MockContentResolver;
|
import android.test.mock.MockContentResolver;
|
||||||
@ -8,7 +9,6 @@ import android.test.mock.MockContext;
|
|||||||
public class MockContextSwappableComponents extends MockContext {
|
public class MockContextSwappableComponents extends MockContext {
|
||||||
|
|
||||||
private PackageManager packageManager;
|
private PackageManager packageManager;
|
||||||
|
|
||||||
private Resources resources;
|
private Resources resources;
|
||||||
private MockContentResolver contentResolver;
|
private MockContentResolver contentResolver;
|
||||||
|
|
||||||
|
@ -45,6 +45,8 @@ public abstract class FDroidProviderTest<T extends FDroidProvider> extends Provi
|
|||||||
public void setUp() throws Exception {
|
public void setUp() throws Exception {
|
||||||
super.setUp();
|
super.setUp();
|
||||||
|
|
||||||
|
FDroidProvider.clearDbHelperSingleton();
|
||||||
|
|
||||||
// Instantiate all providers other than the one which was already created by the base class.
|
// 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
|
// 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
|
// providers, and so we need to be able to insert into those other providers for these
|
||||||
|
@ -18,6 +18,7 @@ import org.fdroid.fdroid.RepoUpdater.UpdateException;
|
|||||||
import org.fdroid.fdroid.data.Apk;
|
import org.fdroid.fdroid.data.Apk;
|
||||||
import org.fdroid.fdroid.data.ApkProvider;
|
import org.fdroid.fdroid.data.ApkProvider;
|
||||||
import org.fdroid.fdroid.data.AppProvider;
|
import org.fdroid.fdroid.data.AppProvider;
|
||||||
|
import org.fdroid.fdroid.data.FDroidProvider;
|
||||||
import org.fdroid.fdroid.data.Repo;
|
import org.fdroid.fdroid.data.Repo;
|
||||||
import org.fdroid.fdroid.data.RepoProvider;
|
import org.fdroid.fdroid.data.RepoProvider;
|
||||||
import org.fdroid.fdroid.data.TempApkProvider;
|
import org.fdroid.fdroid.data.TempApkProvider;
|
||||||
@ -122,12 +123,20 @@ public class MultiRepoUpdaterTest extends InstrumentationTestCase {
|
|||||||
public File getDatabasePath(String name) {
|
public File getDatabasePath(String name) {
|
||||||
return new File(getInstrumentation().getContext().getFilesDir(), "fdroid_test.db");
|
return new File(getInstrumentation().getContext().getFilesDir(), "fdroid_test.db");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Context getApplicationContext() {
|
||||||
|
// Used by the DBHelper singleton instance.
|
||||||
|
return this;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setUp() throws Exception {
|
public void setUp() throws Exception {
|
||||||
super.setUp();
|
super.setUp();
|
||||||
|
|
||||||
|
FDroidProvider.clearDbHelperSingleton();
|
||||||
|
|
||||||
context = new TestContext();
|
context = new TestContext();
|
||||||
|
|
||||||
testFilesDir = TestUtils.getWriteableDir(getInstrumentation());
|
testFilesDir = TestUtils.getWriteableDir(getInstrumentation());
|
||||||
|
Loading…
x
Reference in New Issue
Block a user