SQLite数据库迁移似乎仅部分应用于Espresso测试

Hél*_*tin 6 android sqliteopenhelper android-sqlite android-espresso

我们有一个SQLite数据库和一个对应的SQLiteOpenHelper子类。这个助手有一个onDowngrade我想为其编写Espresso测试的实现。

完整的onDowngrade实现在这里可用。这是它的简化版本:

@Override
public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    db.execSQL("CREATE TABLE IF NOT EXISTS foo_tmp (_id integer primary key, bar text not null, baz text not null);");
    db.execSQL("INSERT INTO foo_tmp(_id,bar,baz) SELECT _id,bar,baz FROM foo;");
    db.execSQL("DROP TABLE IF EXISTS foo;");
    db.execSQL("RENAME TABLE foo_tmp TO foo;");
}
Run Code Online (Sandbox Code Playgroud)

该测试将加载具有很高版本号以及已添加或已删除列的数据库转储。然后,它将获得一个可读的数据库,并确保该版本已降级为当前的预期版本,并且列名是预期的列名。完整的资源在这里。看起来是这样的:

@Test
public void testMigration() throws IOException {
    writeDatabaseFile("database" + File.separator + dbFilename);
    InstancesDatabaseHelper databaseHelper = new InstancesDatabaseHelper();

    SQLiteDatabase db = databaseHelper.getReadableDatabase();
    assertThat(db.getVersion(), is(InstancesDatabaseHelper.DATABASE_VERSION));

    List<String> newColumnNames = InstancesDatabaseHelper.getInstancesColumnNames(db);

    assertThat(newColumnNames, contains(InstancesDatabaseHelper.CURRENT_VERSION_COLUMN_NAMES));
}
Run Code Online (Sandbox Code Playgroud)

如果我将相同的数据库转储手动加载到应用程序中,则一切都会按预期进行。但是,当我运行此测试时,看起来RENAME迁移中的最后一个未执行。如果我注释掉迁移中的最后两个SQL语句(删除原始表并将临时表重命名为原始表名),则可以断言临时表具有预期的内容(是一个显示此内容的提交)。

通过一些实验,我们发现databaseHelper.getReadableDatabase().close();在实例化SQLiteOpenHelper使测试通过之后添加测试。鉴于该onDowngrade呼叫已封装在事务中,所以我不知道这是怎么可能的。

这是否表明我们的onDowngrade实现存在错误?在Espresso测试中触发迁移是否有所不同?

Mar*_*ler 0

可能存在竞争条件,因为 SQLite 是共享资源。

例如。当测试在COMMIT发出最后一条语句之前运行时。

将其包装到事务中(另请参阅SQLite 中的隔离):

if(! BuildConfig.DEBUG) { 
    db.beginTransaction();
} else {
    db.beginTransactionWithListener(new SQLiteTransactionListener() {
        @Override public void onBegin()    {Log.d(LOG_TAG, "onBegin()");}
        @Override public void onCommit()   {Log.d(LOG_TAG, "onCommit()");}
        @Override public void onRollback() {Log.d(LOG_TAG, "onRollback()");}
    });
}

try {

    db.execSQL("CREATE TABLE IF NOT EXISTS foo_tmp (_id integer primary key, bar text not null, baz text not null);");
    db.execSQL("INSERT INTO foo_tmp(_id,bar,baz) SELECT _id,bar,baz FROM foo;");
    db.execSQL("DROP TABLE IF EXISTS foo;");
    db.execSQL("RENAME TABLE foo_tmp TO foo;");
    db.setTransactionSuccessful();

} catch(SQLException e){
    Log.d(LOG_TAG, "" + e.getMessage());
} finally {
    db.endTransaction();
}
db.close();
Run Code Online (Sandbox Code Playgroud)