I'm testing my application with Android Instrumentation tests.
So I have a test-class extending ActivityInstrumentationTestCase2
which contains multiple tests. The code looks like this:
public class ManageProjectsActivityTestextends ActivityInstrumentationTestCase2<ManageProjectsActivity> {
public ManageProjectsActivityTest() {
super("eu.vranckaert.worktime", ManageProjectsActivity.class);
}
@Override
protected void setUp() throws Exception {
getInstrumentation().getTargetContext().deleteDatabase(DaoConstants.DATABASE);
super.setUp();
solo = new Solo(getInstrumentation(), getActivity());
}
@Override
protected void runTest() throws Throwable {
super.runTest();
getActivity().finish();
}
public void testDefaults() {
// My test stuff
}
public void testAddProject() {
// My test stuff
}
}
So the activity which is under test has a list of projects. The list of projects is retrieved from the database. And when no database is available, so when the DB is created, I insert one default project.
So that means when the tests are run this is what I exepct:
But that's not quite what this test-suite does... This is the result of my test-suite:
At the beginning I did not override the runTest() method but I thought that maybe I should end the activity myself to force the re-creation, but it doesn't make any difference.
So it seems that the DB is kept in memory (as even no new DB file is created on the device when I explicitly remove it). Or even the activity, because when putting a breakpoint a in the onCreate of the activity I only get in there once for both tests.
For the maintaining the DB I use ORMLite. You can see my helper class here: http://code.google.com/p/worktime/source/browse/trunk/android-app/src/eu/vranckaert/worktime/dao/utils/DatabaseHelper.java
So my question is how to force the tests to use a different DB all the time...?
A bit tangential to this problem, but I landed here when I was looking for help. Might be helpful to some folks. If you initialize your database with the RenamingDelegatingContext, it cleans the database between runs.
public class DataManagerTest extends InstrumentationTestCase {
private DataManager subject;
@Before
public void setUp() {
super.setUp();
RenamingDelegatingContext newContext = new RenamingDelegatingContext(getInstrumentation().getContext(), "test_");
subject = new DataManager(newContext);
}
// tests...
}
And the associated DataManagerClass.
public class DataManager {
private SQLiteDatabase mDatabase;
private SQLiteOpenHelper mHelper;
private final String mDatabaseName = "table";
private final int mDatabaseVersion = 1;
protected DataManager(Context context) {
this.mContext = context;
createHelper();
}
private void createHelper() {
mHelper = new SQLiteOpenHelper(mContext, mDatabaseName, null, mDatabaseVersion) {
@Override
public void onCreate(SQLiteDatabase sqLiteDatabase) {
// createTable...
}
@Override
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int oldVersion, int newVersion) {
// upgrade table
}
};
}
...
}
mDb.delete(DATABASE_TABLE_NAME, null, null);
That is indeed the solution/way-to-go...
I changed the first line in my setUp(..) method to this:
cleanUpDatabase(tableList);
And then I added the method cleanUpDatabse(..) liek this:
private void cleanUpDatabase(List<String> dbTables) {
Log.i(LOG_TAG, "Preparing to clean up database...");
DatabaseHelper dbHelper = new DatabaseHelper(getInstrumentation().getTargetContext());
ConnectionSource cs = dbHelper.getConnectionSource();
SQLiteDatabase db = dbHelper.getWritableDatabase();
Log.i(LOG_TAG, "Dropping all tables");
for (String table : dbTables) {
db.execSQL("DROP TABLE IF EXISTS " + table);
}
Log.i(LOG_TAG, "Executing the onCreate(..)");
dbHelper.onCreate(db, cs);
Log.i(LOG_TAG, "Verifying the data...");
for (String table : dbTables) {
Cursor c = db.query(table, new String[]{"id"}, null, null, null, null, null);
int count = c.getCount();
if (count != 1 && (table.equals("project") || table.equals("task"))) {
dbHelper.close();
Log.e(LOG_TAG, "We should have 1 record for table " + table + " after cleanup but we found " + count + " record(s)");
throw new RuntimeException("Error during cleanup of DB, exactly one record should be present for table " + table + " but we found " + count + " record(s)");
} else if (count != 0 && !(table.equals("project") || table.equals("task"))) {
dbHelper.close();
Log.e(LOG_TAG, "We should have 0 records for table " + table + " after cleanup but we found " + count + " record(s)");
throw new RuntimeException("Error during cleanup of DB, no records should be present for table " + table + " but we found " + count + " record(s)");
}
}
Log.i(LOG_TAG, "The database has been cleaned!");
dbHelper.close();
}
This piece of code gets executed before every test, which makes all my tests independent from each other.
Caution: In order to retrieve a reference to your DatabaseHelper (your own implementation off course ;) ) you cannot call getActivity()
because that will launch your activity (and thus do all your initial DB loading (if any..)
android.support.test.InstrumentationRegistry
's getTargetContext and, counterintuitively perhaps, getContext should do the trick:
Use getContext for deleting database (not getTargetContext).
getContext().deleteDatabase(DbHelper.DATABASE_NAME);
public class DbHelperTest {
private DbHelper mDb;
@Before
public void setUp() throws Exception {
getContext().deleteDatabase(DbHelper.DATABASE_NAME);
mDb = new DbHelper(getTargetContext());
}
@After
public void tearDown() throws Exception {
mDb.close();
}
@Test
public void onCreate() throws Exception {
mDb.onCreate(mDb.getWritableDatabase());
}
@Test
public void onUpgrade() throws Exception {
mDb.onUpgrade(mDb.getWritableDatabase(), 1, 2);
}
@Test
public void dropTable() throws Exception {
String tableName = "mesa";
mDb.getReadableDatabase().execSQL("CREATE TABLE "
+ tableName + "(_id INTEGER PRIMARY KEY AUTOINCREMENT)");
mDb.dropTable(mDb.getWritableDatabase(), tableName);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With