单元测试的数据库资产

database asset for unitTest

对于我的单元测试,我在 SQLite 数据库中收集了真实世界的传感器数据。我需要这些数据来创建我的测试。我尝试了以下两种方法都没有成功。

我真的被这个问题难住了,因为通常 SQLiteOpenHelper 可以完美地加载 /data/data/packageName/databases/ 中的任何数据库。

我试过了android-sqlite-asset-helper:

val targetContext by lazy { InstrumentationRegistry.getTargetContext() }
val testContext by lazy { InstrumentationRegistry.getContext() }

const val TEST_DB_NAME = "testdb.sqlite"
const val VERSION = 1018

class TestDatabase(context: Context) : 
    SQLiteAssetHelper(context, TEST_DB_NAME, null, null, VERSION) {
    ...  
}

但是 none 的上下文有效。使用 testContext 无法将数据库写入文件系统,使用 targetContext 则无法访问 androidTest/assets/databases/testdb.sqlite.

当我尝试手动复制 () 时:

const val DB_PATH = "/data/data/de.leo.smartTrigger/databases/"

@Throws(IOException::class)
private fun copyDatabase(testContext: Context) {
    val inputStream = testContext.getAssets().open("databases/$TEST_DB_NAME")
    val outFileName = DB_PATH + TEST_DB_NAME
    val outputStream = FileOutputStream(outFileName)

    val buffer = ByteArray(1024)
    var length: Int = inputStream.read(buffer)
    while (length > 0) {
        outputStream.write(buffer, 0, length)
        length = inputStream.read(buffer)
    }

    outputStream.flush()
    outputStream.close()
    inputStream.close()
}

//after
copyDatabase(testContext)
val db = SQLiteDatabase.openDatabase(DB_PATH + TEST_DB_NAME, null, SQLiteDatabase.CREATE_IF_NECESSARY)
//yields an empty database although 
File(DB_PATH + TEST_DB_NAME).exists() == true // true

如何从 androidTest/assets/databases/testdb.sqlite 加载数据库? in-memory的加分项,因为反正我考完都会被丢弃

我找到了解决方案:

Convert the database to input-statements

sqlite testdb.sqlite .dump > testdb.sql

将此文件放入 androidTest/assets/databases/ 然后创建数据库:

    class MyDatabaseOpenHelper(val context: Context,
                           version: Int = 1) : SQLiteOpenHelper
                                                  (context,
                                                   null,
                                                   null,
                                                   version,
                                                   null) {
    override fun onCreate(db: SQLiteDatabase?) {
        BufferedReader(InputStreamReader(context.getAssets().open("databases/testdb.sql"))).apply {
            lines().forEach {
                try {
                    db!!.execSQL(it)
                } catch (e: SQLiteException) {
                    Log.w("read test db", e)
                }
            }
            close()
        }
    }

    override fun onUpgrade(db: SQLiteDatabase?, oldVersion: Int, newVersion: Int) {
        //noop load from file
    }
}

通过不提供名称,我们从 sql 语句创建了一个内存数据库。

这个解决方案并不完美,因为它需要在更新测试数据库时手动执行步骤,但它对我有用。