Testing on Android - start with a clean database for each test

I am testing my application using Android Instrumentation tests.

So, I have a test class extending ActivityInstrumentationTestCase2 that contains several tests. The code is as follows:

 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 } } 

Thus, the activity being tested has a list of projects. The list of projects is retrieved from the database. And when the database is unavailable, so when the database is created, I insert one project by default.

So this means that when tests are executed, this is what I exepct:

  • The database, if available, is deleted on the device
  • The first test has begun (and thus, an activity has been launched that creates my database with one project)
  • The tests use a newly created database, so the value is with only one project, during the test a second project is created
  • The first test is complete and the setUp () method is called again
  • The database that must exist now is deleted again
  • The second test is launched (and thus the activity is launched, which creates my database with one project)
  • The second test also ends

But this is not exactly what this test package does ... This is the result of my test suite:

  • The database, if available, is deleted on the device
  • The first test has begun (and thus, an activity has been launched that creates my database with one project)
  • The tests use a newly created database, so the value is with only one project, during the test a second project is created
  • The first test is complete and the setUp () method is called again
  • The database that must exist now is deleted again
  • And here it is: the second test is running (but my database is not created again !!! I donโ€™t see the file on the device either ...), and the test should display only one project on but it shows already two !!!
  • The second test also ends, but it does not work, because I have two projects at the beginning ...

At first, I did not override the runTest () method, but I thought that maybe I should finish the process itself in order to force the re-creation, but that does not make any difference.

Thus, it seems that the database is stored in memory (since even a new DB file is not created on the device when I explicitly delete it). Or even activity, because when you put a breakpoint a in onCreate activity, I only go there once for both tests.

To support the database, 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 make tests use different databases all the time ...?

+4
source share
5 answers

A little about this problem, but I landed here when I was looking for help. May be useful to some people. If you initialize your database using a 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 } }; } ... } 
+3
source
 mDb.delete(DATABASE_TABLE_NAME, null, null); 

This is really a solution / way to work ...

I changed the first line in my setUp (..) method to this:

 cleanUpDatabase(tableList); 

And then I added the cleanUpDatabse (..) method 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 runs before each test, which makes all my tests independent of each other.

Note: in order to get a link to your DatabaseHelper (your own implementation is off-course;)), you cannot call getActivity() , because it will start your activity (and, therefore, will do all your initial DB loading (if any ..)

+5
source

you are trying to run a time when all tabular data removes an alternative native solution.

 mDb.delete(DATABASE_TABLE_NAME, null, null); 
+2
source

Since my db is encrypted, I need to delete the actual db file after each test case. I was not able to create deleteDatabase from RenamingDelegatingContext , because RenamingDelegatingContext for some reason could not find the previously created db.

Solution for subclass AndroidTestCase :

 @Override protected void setUp() throws Exception { super.setUp(); mContext = new RenamingDelegatingContext(getContext(), TEST_DB_PREFIX); // create db here } @Override protected void tearDown() throws Exception { // Making RenamingDelegatingContext find the test database ((RenamingDelegatingContext) mContext).makeExistingFilesAndDbsAccessible(); mContext.deleteDatabase(DB_NAME); super.tearDown(); } 
+1
source

InstrumentationRegistry โ†’ getContext โ†’ deleteDatabase

android.support.test.InstrumentationRegistry getTargetContext and, perhaps intuitively, getContext should do the trick:


Description

Use getContext to delete the database ( not getTargetContext ).

getContext().deleteDatabase(DbHelper.DATABASE_NAME);


Example

 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); } } 
+1
source

Source: https://habr.com/ru/post/1402605/


All Articles