Тестирование Android - начните с чистой базы данных для каждого теста - PullRequest
6 голосов
/ 21 марта 2012

Я тестирую свое приложение с помощью тестов Android Instrumentation.

Итак, у меня есть расширение класса теста ActivityInstrumentationTestCase2, которое содержит несколько тестов.Код выглядит следующим образом:

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

Таким образом, тестируемое действие содержит список проектов.Список проектов извлекается из базы данных.И когда база данных недоступна, поэтому при создании БД я вставляю один проект по умолчанию.

Так что это означает, что при запуске тестов это то, что я исключаю:

  1. база данных, если имеется, удаляется на устройстве
  2. Первый тест запускается (и, таким образом, запускается действие, которое создает мою БД с одним проектом)
  3. В тестах используется вновь созданная БД,то есть, имея в виду только один проект, во время теста создается второй проект
  4. Первый тест завершен, и метод setUp () вызывается снова
  5. База данных, которая должна существовать сейчас,снова удален
  6. Второй тест запущен (и, таким образом, запускается действие, которое создает мою БД с одним проектом)
  7. Второй тест также завершается

Но этоне совсем то, что делает этот набор тестов ... Это результат моего набора тестов:

  1. База данных, если имеется, удаляется на устройстве
  2. Первый тестзапущен (и таким образомЗапущено действие, которое создает мою БД с одним проектом)
  3. В тестах используется только что созданная БД, то есть только с одним проектом, во время теста создается второй проект
  4. Первый тестзавершается и метод setUp () вызывается снова
  5. База данных, которая должна существовать сейчас, снова удаляется
  6. И вот оно: Второй тест запущен (но мойБД не создается снова !!!Я также не вижу файла на устройстве ...) и тест должен отображать только один проект в начале, но он отображает уже два !!!
  7. Второй тест также завершается, но не проходит, потому чтоВ начале у меня есть два проекта ...

Вначале я не переопределял метод runTest (), но подумал, что, возможно, мне следует самому завершить действие, чтобы вызвать повторное создание, ноэто не имеет никакого значения.

Так что кажется, что БД хранится в памяти (так как даже новый файл БД не создается на устройстве, когда я явно удаляю его).Или даже действия, потому что, когда я ставлю точку останова a в onCreate действия, я попадаю туда только один раз для обоих тестов.

Для обслуживания БД я использую ORMLite.Вы можете увидеть мой вспомогательный класс здесь: http://code.google.com/p/worktime/source/browse/trunk/android-app/src/eu/vranckaert/worktime/dao/utils/DatabaseHelper.java

Так что мой вопрос в том, как заставить тесты постоянно использовать разные БД ...?

Ответы [ 5 ]

5 голосов
/ 22 марта 2012
mDb.delete(DATABASE_TABLE_NAME, null, null); 

Это действительно решение / путь ...

Я изменил первую строку в моем методе setUp (..) на это:

cleanUpDatabase(tableList);

А затем я добавил метод cleanUpDatabse (..), например:

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();
}

Этот фрагмент кода выполняется перед каждым тестом, что делает все мои тесты независимыми друг от друга.

Внимание: чтобы получить ссылку на ваш DatabaseHelper (ваша собственная реализация вне курса;)), вы не можете вызвать getActivity(), потому что это запустит вашу деятельность (и, таким образом, выполнит всю вашу начальную загрузку БД (если есть ..)

5 голосов
/ 26 ноября 2014

Немного касательно этой проблемы, но я попал сюда, когда искал помощи. Может быть полезным для некоторых людей. Если вы инициализируете базу данных с помощью RenamingDelegatingContext, она очищает базу данных между запусками.

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

И связанный 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
      }
    };
  }
    ...
}
4 голосов
/ 27 апреля 2017

InstrumentationRegistry → getContext → deleteDatabase

android.support.test.InstrumentationRegistry s getTargetContext и, возможно, нелогичным образом, getContext должны выполнить трюк:


Синопсис

Используйте getContext для удаления базы данных ( не getTargetContext ).

getContext().deleteDatabase(DbHelper.DATABASE_NAME);


* 1 028 * Пример * +1029 *
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);
    }
}
2 голосов
/ 22 марта 2012

вы пытаетесь запустить время все данные таблицы удалить альтернативное решение.

mDb.delete(DATABASE_TABLE_NAME, null, null); 
1 голос
/ 07 июля 2016

Поскольку мой БД зашифрован, мне нужно было удалять фактический файл БД после каждого теста.У меня были проблемы с deleteDatabase из RenamingDelegatingContext, поскольку RenamingDelegatingContext по какой-то причине не смог найти ранее созданный дБ.

Решение для 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();
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...