lateinit 属性 colorPalettesDB 尚未初始化 - 将第二个 Room 数据库添加到应用程序会导致所有 Espresso 测试失败
lateinit property colorPalettesDB has not been initialized - adding second Room database to application causes all Espresso tests to fail
我正在为 Android 创建一个像素艺术编辑器应用程序,我有两个数据库,一个存储用户的创作,另一个存储用户的调色板。
这是调色板数据库的代码:
package com.realtomjoney.pyxlmoose.database
import android.content.Context
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
import androidx.sqlite.db.SupportSQLiteDatabase
import com.realtomjoney.pyxlmoose.converters.JsonConverter
import com.realtomjoney.pyxlmoose.dao.ColorPalettesDao
import com.realtomjoney.pyxlmoose.models.ColorPalette
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import java.util.concurrent.Executors
@Database(entities = [ColorPalette::class], version = 3)
abstract class ColorPalettesDatabase: RoomDatabase() {
abstract fun colorPalettesDao(): ColorPalettesDao
companion object {
private var instance: ColorPalettesDatabase? = null
fun getDatabase(context: Context): ColorPalettesDatabase {
if (instance == null) {
synchronized(ColorPalettesDatabase::class) {
if (instance == null) instance = Room.databaseBuilder(context.applicationContext, ColorPalettesDatabase::class.java, AppData.colorPalettesDBFileName).fallbackToDestructiveMigration().addCallback(object : RoomDatabase.Callback() {
override fun onCreate(db: SupportSQLiteDatabase) {
super.onCreate(db)
Executors.newSingleThreadExecutor().execute {
CoroutineScope(Dispatchers.IO).launch {
instance?.colorPalettesDao()?.insertColorPalette(ColorPalette("Default color palette", JsonConverter.convertListOfIntToJsonString(ColorDatabase.toList()), true))
}
}
}
}).allowMainThreadQueries().build()
}
}
return instance!!
}
}
}
首次创建 Room 数据库时,会添加 'Default' 调色板。
道:
@Dao
interface ColorPalettesDao {
@Insert
suspend fun insertColorPalette(colorPalette: ColorPalette)
@Query("SELECT * FROM ColorPalette")
fun getAllColorPalettes(): LiveData<List<ColorPalette>>
@Query("DELETE FROM ColorPalette WHERE objId=:colorPaletteId")
fun deleteColorPalette(colorPaletteId: Int)
@Query("UPDATE ColorPalette SET item_color_palette_color_data=:colorData WHERE objId=:id_t")
fun updateColorPaletteColorData(colorData: String, id_t: Int)
}
应用程序数据:
class AppData {
companion object {
var pixelArtDBFileName = "pixel_art_db"
lateinit var pixelArtDB: PixelArtDatabase
var colorPalettesDBFileName = "color_palettes_db"
lateinit var colorPalettesDB: ColorPalettesDatabase
}
}
数据像这样加载到 RecyclerView 中:
fun CanvasActivity.extendedSetUpRecyclerView() {
val layoutManager = GridLayoutManager(this, 1)
layoutManager.orientation = LinearLayoutManager.HORIZONTAL
binding.activityCanvasColorPickerRecyclerView.layoutManager = layoutManager
AppData.colorPalettesDB.colorPalettesDao().getAllColorPalettes().observe(this) {
val toShow = if (fromDB != null) fromDB else it.first()
binding.activityCanvasColorPickerRecyclerView.adapter = ColorPickerAdapter(toShow!!, this)
}
}
以下是我的一些 Espresso 测试:
@LargeTest
@RunWith(AndroidJUnit4ClassRunner::class)
class CanvasActivityTest {
@get:Rule
var activityTestRule = ActivityScenarioRule(CanvasActivity::class.java)
@Test fun uitest_activityCanvasRootLayout_childViews_doNotExist() {
for (id in EspressoUtilities.getActivityCanvasRootLayoutChildElementIds()) onView(withId(id)).check(matches(isDisplayed()))
}
@Test fun uitest_fullscreenMenuItem_isDisplayed() {
onView(withId(R.id.fullscreen)).check(matches(isDisplayed()))
}
@Test fun uitest_undoMenuItem_isDisplayed() {
onView(withId(R.id.undo)).check(matches(isDisplayed()))
}
@Test fun uitest_zoomIn_isDisplayed() {
onView(withId(R.id.zoom_in)).check(matches(isDisplayed()))
}
@Test fun uitest_zoomOut_isDisplayed() {
onView(withId(R.id.zoom_out)).check(matches(isDisplayed()))
}
@Test fun uitest_saveProject_isDisplayed() {
onView(withId(R.id.save_project)).check(matches(isDisplayed()))
}
}
运行 Espresso 测试导致以下异常:
kotlin.UninitializedPropertyAccessException: lateinit property colorPalettesDB has not been initialized
at com.realtomjoney.pyxlmoose.database.AppData$Companion.getColorPalettesDB(AppData.kt:9)
at com.realtomjoney.pyxlmoose.activities.canvas.CanvasActivity_setUpRecyclerViewKt.extendedSetUpRecyclerView(CanvasActivity+setUpRecyclerView.kt:15)
at com.realtomjoney.pyxlmoose.activities.canvas.CanvasActivity.setUpRecyclerView(CanvasActivity.kt:45)
at com.realtomjoney.pyxlmoose.activities.canvas.CanvasActivity_onCreateKt.extendedOnCreate(CanvasActivity+onCreate.kt:13)
at com.realtomjoney.pyxlmoose.activities.canvas.CanvasActivity.onCreate(CanvasActivity.kt:19)
at android.app.Activity.performCreate(Activity.java:8051)
at android.app.Activity.performCreate(Activity.java:8031)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1329)
at androidx.test.runner.MonitoringInstrumentation.callActivityOnCreate(MonitoringInstrumentation.java:769)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3612)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3796)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:103)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2214)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loopOnce(Looper.java:201)
at android.os.Looper.loop(Looper.java:288)
at android.app.ActivityThread.main(ActivityThread.java:7842)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1003)
这很奇怪,因为 colorPalettesDB
应该已经在这个阶段初始化了。存储用户创建的其他数据库没有引起任何问题,但由于某种原因 ColorPalettesDatabase
是导致这些异常的数据库。在 onCreate
和 Espresso 代码中第二次初始化它并没有解决问题,所以我很困惑如何解决这个问题,因为我不确定错误的来源是什么。
正在添加
Room.inMemoryDatabaseBuilder(ApplicationProvider.getApplicationContext(),ColorPalettesDatabase::class.java).build()
...无法解决问题。
这里是数据库初始化的地方:
fun MainActivity.initializeRoomDatabases() {
AppData.pixelArtDB = PixelArtDatabase.getDatabase(this)
AppData.colorPalettesDB = ColorPalettesDatabase.getDatabase(this)
}
public override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setBindings()
setOnClickListeners()
setTitle()
initializeRoomDatabases()
}
请在您的测试中使用下面的代码。
Room.inMemoryDatabaseBuilder(context, TestDatabase::class.java).build()
更多信息:Test and debug your database
更新:
错误提示您必须以某种方式初始化 colorPalettesDB。也许你应该在 DI 中定义它。
更新二:
我想也许 CanvasActivity.extendedSetUpRecyclerView() 在 Activity 中的 MainActivity.initializeRoomDatabases() 之前调用了方法,所以 AppData.colorPalettesDB 没有被初始化。
我正在为 Android 创建一个像素艺术编辑器应用程序,我有两个数据库,一个存储用户的创作,另一个存储用户的调色板。
这是调色板数据库的代码:
package com.realtomjoney.pyxlmoose.database
import android.content.Context
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
import androidx.sqlite.db.SupportSQLiteDatabase
import com.realtomjoney.pyxlmoose.converters.JsonConverter
import com.realtomjoney.pyxlmoose.dao.ColorPalettesDao
import com.realtomjoney.pyxlmoose.models.ColorPalette
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import java.util.concurrent.Executors
@Database(entities = [ColorPalette::class], version = 3)
abstract class ColorPalettesDatabase: RoomDatabase() {
abstract fun colorPalettesDao(): ColorPalettesDao
companion object {
private var instance: ColorPalettesDatabase? = null
fun getDatabase(context: Context): ColorPalettesDatabase {
if (instance == null) {
synchronized(ColorPalettesDatabase::class) {
if (instance == null) instance = Room.databaseBuilder(context.applicationContext, ColorPalettesDatabase::class.java, AppData.colorPalettesDBFileName).fallbackToDestructiveMigration().addCallback(object : RoomDatabase.Callback() {
override fun onCreate(db: SupportSQLiteDatabase) {
super.onCreate(db)
Executors.newSingleThreadExecutor().execute {
CoroutineScope(Dispatchers.IO).launch {
instance?.colorPalettesDao()?.insertColorPalette(ColorPalette("Default color palette", JsonConverter.convertListOfIntToJsonString(ColorDatabase.toList()), true))
}
}
}
}).allowMainThreadQueries().build()
}
}
return instance!!
}
}
}
首次创建 Room 数据库时,会添加 'Default' 调色板。
道:
@Dao
interface ColorPalettesDao {
@Insert
suspend fun insertColorPalette(colorPalette: ColorPalette)
@Query("SELECT * FROM ColorPalette")
fun getAllColorPalettes(): LiveData<List<ColorPalette>>
@Query("DELETE FROM ColorPalette WHERE objId=:colorPaletteId")
fun deleteColorPalette(colorPaletteId: Int)
@Query("UPDATE ColorPalette SET item_color_palette_color_data=:colorData WHERE objId=:id_t")
fun updateColorPaletteColorData(colorData: String, id_t: Int)
}
应用程序数据:
class AppData {
companion object {
var pixelArtDBFileName = "pixel_art_db"
lateinit var pixelArtDB: PixelArtDatabase
var colorPalettesDBFileName = "color_palettes_db"
lateinit var colorPalettesDB: ColorPalettesDatabase
}
}
数据像这样加载到 RecyclerView 中:
fun CanvasActivity.extendedSetUpRecyclerView() {
val layoutManager = GridLayoutManager(this, 1)
layoutManager.orientation = LinearLayoutManager.HORIZONTAL
binding.activityCanvasColorPickerRecyclerView.layoutManager = layoutManager
AppData.colorPalettesDB.colorPalettesDao().getAllColorPalettes().observe(this) {
val toShow = if (fromDB != null) fromDB else it.first()
binding.activityCanvasColorPickerRecyclerView.adapter = ColorPickerAdapter(toShow!!, this)
}
}
以下是我的一些 Espresso 测试:
@LargeTest
@RunWith(AndroidJUnit4ClassRunner::class)
class CanvasActivityTest {
@get:Rule
var activityTestRule = ActivityScenarioRule(CanvasActivity::class.java)
@Test fun uitest_activityCanvasRootLayout_childViews_doNotExist() {
for (id in EspressoUtilities.getActivityCanvasRootLayoutChildElementIds()) onView(withId(id)).check(matches(isDisplayed()))
}
@Test fun uitest_fullscreenMenuItem_isDisplayed() {
onView(withId(R.id.fullscreen)).check(matches(isDisplayed()))
}
@Test fun uitest_undoMenuItem_isDisplayed() {
onView(withId(R.id.undo)).check(matches(isDisplayed()))
}
@Test fun uitest_zoomIn_isDisplayed() {
onView(withId(R.id.zoom_in)).check(matches(isDisplayed()))
}
@Test fun uitest_zoomOut_isDisplayed() {
onView(withId(R.id.zoom_out)).check(matches(isDisplayed()))
}
@Test fun uitest_saveProject_isDisplayed() {
onView(withId(R.id.save_project)).check(matches(isDisplayed()))
}
}
运行 Espresso 测试导致以下异常:
kotlin.UninitializedPropertyAccessException: lateinit property colorPalettesDB has not been initialized
at com.realtomjoney.pyxlmoose.database.AppData$Companion.getColorPalettesDB(AppData.kt:9)
at com.realtomjoney.pyxlmoose.activities.canvas.CanvasActivity_setUpRecyclerViewKt.extendedSetUpRecyclerView(CanvasActivity+setUpRecyclerView.kt:15)
at com.realtomjoney.pyxlmoose.activities.canvas.CanvasActivity.setUpRecyclerView(CanvasActivity.kt:45)
at com.realtomjoney.pyxlmoose.activities.canvas.CanvasActivity_onCreateKt.extendedOnCreate(CanvasActivity+onCreate.kt:13)
at com.realtomjoney.pyxlmoose.activities.canvas.CanvasActivity.onCreate(CanvasActivity.kt:19)
at android.app.Activity.performCreate(Activity.java:8051)
at android.app.Activity.performCreate(Activity.java:8031)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1329)
at androidx.test.runner.MonitoringInstrumentation.callActivityOnCreate(MonitoringInstrumentation.java:769)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3612)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3796)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:103)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2214)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loopOnce(Looper.java:201)
at android.os.Looper.loop(Looper.java:288)
at android.app.ActivityThread.main(ActivityThread.java:7842)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1003)
这很奇怪,因为 colorPalettesDB
应该已经在这个阶段初始化了。存储用户创建的其他数据库没有引起任何问题,但由于某种原因 ColorPalettesDatabase
是导致这些异常的数据库。在 onCreate
和 Espresso 代码中第二次初始化它并没有解决问题,所以我很困惑如何解决这个问题,因为我不确定错误的来源是什么。
正在添加
Room.inMemoryDatabaseBuilder(ApplicationProvider.getApplicationContext(),ColorPalettesDatabase::class.java).build()
...无法解决问题。
这里是数据库初始化的地方:
fun MainActivity.initializeRoomDatabases() {
AppData.pixelArtDB = PixelArtDatabase.getDatabase(this)
AppData.colorPalettesDB = ColorPalettesDatabase.getDatabase(this)
}
public override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setBindings()
setOnClickListeners()
setTitle()
initializeRoomDatabases()
}
请在您的测试中使用下面的代码。
Room.inMemoryDatabaseBuilder(context, TestDatabase::class.java).build()
更多信息:Test and debug your database
更新:
错误提示您必须以某种方式初始化 colorPalettesDB。也许你应该在 DI 中定义它。
更新二:
我想也许 CanvasActivity.extendedSetUpRecyclerView() 在 Activity 中的 MainActivity.initializeRoomDatabases() 之前调用了方法,所以 AppData.colorPalettesDB 没有被初始化。