6

I am trying to test the insertion and retrieval methods for my SQLiteOpenHelper subclass in an Android application. The SQLLiteHelper subclass exists in the app under test, and creates a database in the installation folder. However, the unit test exists in a InstrumentTestCase in the test app, and I would like to create a test database in the test app.

Unfortunately, if I try to create / open a database in the test app, I get the following exception:

android.database.sqlite.SQLiteException: unable to open database file
at android.database.sqlite.SQLiteDatabase.dbopen(Native Method)
at android.database.sqlite.SQLiteDatabase.<init>(SQLiteDatabase.java:1584)
at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:638)
at android.database.sqlite.SQLiteOpenHelper.getReadableDatabase(SQLiteOpenHelper.java:168)
at com.kizoom.android.mybus.storage.MyStopsDatabase.getMyStops(MyStopsDatabase.java:63)
at com.kizoom.mybus.test.MyStopsDatabaseTest.testGetMyStops(MyStopsDatabaseTest.java:24)
at java.lang.reflect.Method.invokeNative(Native Method)
at android.test.InstrumentationTestCase.runMethod(InstrumentationTestCase.java:191)
at android.test.InstrumentationTestCase.runTest(InstrumentationTestCase.java:181)
at android.test.AndroidTestRunner.runTest(AndroidTestRunner.java:164)
at android.test.AndroidTestRunner.runTest(AndroidTestRunner.java:151)
at android.test.InstrumentationTestRunner.onStart(InstrumentationTestRunner.java:425)
at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:1520)

The following information appears in LogCat.

02-21 11:52:16.204: ERROR/Database(1454): sqlite3_open_v2("/data/data/com.kizoom.mybus.test/databases/MyStops", &handle, 6, NULL) failed

02-21 11:52:16.204: ERROR/SQLiteOpenHelper(1454): Couldn't open MyStops for writing (will try read-only):

02-21 11:52:16.204: ERROR/SQLiteOpenHelper(1454): android.database.sqlite.SQLiteException: unable to open database file

02-21 11:52:16.204: ERROR/SQLiteOpenHelper(1454):     at android.database.sqlite.SQLiteDatabase.dbopen(Native Method)

02-21 11:52:16.204: ERROR/SQLiteOpenHelper(1454):     at android.database.sqlite.SQLiteDatabase.<init>(SQLiteDatabase.java:1584)

02-21 11:52:16.204: ERROR/SQLiteOpenHelper(1454):     at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:638)

Does anybody know why this would fail?

Harry Joy
  • 58,650
  • 30
  • 162
  • 207
  • 1
    The error suggests that you are not creating your database - or possibly, you are creating it outside of `SQLiteOpenHelper.onCreate()` (since it cannot be opened) and therefore when you use other `SQLiteOpenHelper` convenience methods, they are unaware of your database. Please post your code where you create the database, and your `onCreate` for your subclassed `SQLiteOpenHelper`. – RivieraKid Feb 23 '11 at 09:46
  • The correct answer is this one: http://stackoverflow.com/a/8488722/1432640 – stillwaiting Aug 05 '15 at 21:15

2 Answers2

35

Instead of using getInstrumentation().getContext() for the context during create of the db helper, I changed it to getInstrumentation().getTargetContext() and it works.

Willi Mentzel
  • 27,862
  • 20
  • 113
  • 121
Aviral
  • 1,141
  • 1
  • 10
  • 16
  • 1
    There's a very real different between Instrumentation#getContext() which returns the context of the testing application and Instrumentation#getTargetContext() which returns the context of your actual application. This means that using Instrumentation#getTargetContext#() is risky because your tests could modify files that are actually used by your application. – Martin Devillers Oct 05 '15 at 19:33
4

I use the following setUp()-Method in my TestDatabaseHelper*-TestCases:

@Override
    protected void setUp() throws Exception {
        super.setUp();
        final SQLiteDatabase db = SQLiteDatabase.create(null);
        Context context = new MockContext() {
            @Override
            public SQLiteDatabase openOrCreateDatabase(String file, int mode, SQLiteDatabase.CursorFactory factory) {
                return db;
            };
        };
        mHelper = new MyCustomSubclassOfDatabaseHelper(context);
        mDb = mHelper.getWritableDatabase();
        wipeData(mDb);
    }
    public void wipeData(SQLiteDatabase db) {
        db.execSQL("DELETE FROM " + TABLENAME + ";");
    }

It's pretty cool because documentation says about SQLiteDatabase.create():

Create a memory backed SQLite database. Its contents will be destroyed when the database is closed.

So your testdatabase is not persisted and you can easily test your custom insert/update/query/delete methods.

Hope this helps. If there are any questions left, feel free to ask.

Cheers, Christoph

Christoph Haefner
  • 1,093
  • 1
  • 9
  • 25
  • Hey @Chistoph what is wipedata method and how i can use this to test database operation ?Thanks – Antwan Oct 12 '16 at 14:45
  • Hi @Tony, took me a while to find code from 4 years ago (the question is actually 5 years old). I updated the code example to include wipeData, have a look. The idea is that you can now test the DatabaseHelper without worries that there is data left in the SQLiteDatabase from other testruns. – Christoph Haefner Oct 13 '16 at 08:21
  • Thanks Alot, I will check it – Antwan Oct 13 '16 at 09:05