Я пытаюсь создать приложение для Android в соответствии с рекомендуемой структурой проектирования .
Допустим, есть UserRepository
для работы с пользователями.Тем не менее, я хотел бы иметь определенные настройки в приложении, например, «Показать изображение профиля», «Сортировать по» и т. Д. Я хотел бы сохранить эти настройки в базе данных комнат, как пользователи.
Насколько я понимаю, самый чистый способ - иметь отдельные UserRepository
и SettingsRepository
.И, конечно, в настройках должна быть своего рода модель, назовем ее SettingsModel
, чтобы можно было получить настройки, например, Map
.Обратите внимание, что это не ViewModel
, он не имеет ничего общего с пользовательским интерфейсом.
Затем UserRepository
должен реализовать свой собственный бизнес (управление пользователями), как в примере, связанном выше.,Кроме того, он также должен иметь зависимость SettingsModel
, чтобы он мог легко извлекать настройки, которые влияют на способ извлечения пользователей.
SettingsModel
необходимо включить «необработанную базу данных»данные "в карту, чтобы я мог получить настройки, как это: settings.show_profile_pictures
и settings.sort_by
, и т. д. Чтобы добиться этого, мне нужно извлечь данные из LiveData
, что подразумевает, что мне нужно наблюдатьчто LiveData
, чтобы я мог обновлять Map
всякий раз, когда меняются настройки.
И тут возникает проблема: для метода observe()
требуется LifecycleOwner
, который я не могу предоставить в своих тестах,
1-я попытка: макет с Mockito
Это был бы инструментальный тест, потому что таким образом у меня был доступ к Activity
, который необходим для получения DAO.
Я пытаюсь @Inject
сделать это с Кинжалом, но насмешка не удалась:
class SettingsRepositoryTest {
private lateinit var settingsDao: SettingsDao
@Mock
private lateinit var mockLifecycleOwner: LifecycleOwner
@Before
fun createDb(){
MockitoAnnotations.initMocks(LifecycleOwner::class.java)
val appContext = InstrumentationRegistry.getTargetContext()
val db = Room.inMemoryDatabaseBuilder(appContext, CurrencyConverterDb::class.java).allowMainThreadQueries().build()
settingsDao = db.settingsDao()
}
@Test
fun testSettingsMap() {
val repo = SettingsRepository(settingsDao, mockLifecycleOwner) // throws the exception here
}
}
Исключение:
kotlin.UninitializedPropertyAccessException: lateinit property mockLifecycleOwner has not been initialized
at com.helmet91.currencyconverter.repositories.SettingsRepositoryTestInst.testSettingsMap(SettingsRepositoryTestInst.kt:46)
2-я попытка: использовать Roboelectric для создания AppCompatActivity
, который на самом деле является LifecycleOwner
.
Это не инструментальный тест, потому что Roboelectric не работает в среде androidTest.
Activity
все еще нужно высмеивать, однако он выбрасывает NullPointerException
.Единственный способ, которым я могу придумать, - это пройти через этот стек исключений и смоделировать все в нем, если это вообще возможно.Но это звучит безумно для меня.Должно быть лучшее решение.
class SettingsRepositoryTest {
private lateinit var settingsDao: SettingsDao
private lateinit var activity: AppCompatActivity
@Before
fun createDb(){
val built = Robolectric.buildActivity(MainActivity::class.java) // throws the exception here
val created = built.create()
val controller = created.start()
activity = controller.get() as AppCompatActivity
val db = Room.inMemoryDatabaseBuilder(activity, CurrencyConverterDb::class.java).allowMainThreadQueries().build()
settingsDao = db.settingsDao()
}
@Test
fun testSettingsMap() {
val repo = SettingsRepository(settingsDao, activity)
val settingsMap = repo.getSettings()
val settingsEntity = Settings(1, "show_flags", "1", "bool")
settingsDao.insert(settingsEntity)
assertTrue(settingsMap.show_flags)
}
}
Исключение:
java.lang.NullPointerException
at org.robolectric.internal.bytecode.ShadowImpl.extract(ShadowImpl.java:17)
at org.robolectric.shadow.api.Shadow.extract(Shadow.java:25)
at org.robolectric.Shadows.shadowOf(Shadows.java:1215)
at org.robolectric.shadows.CoreShadowsAdapter.getMainLooper(CoreShadowsAdapter.java:23)
at org.robolectric.android.controller.ComponentController.<init>(ComponentController.java:29)
at org.robolectric.android.controller.ComponentController.<init>(ComponentController.java:21)
at org.robolectric.android.controller.ActivityController.<init>(ActivityController.java:33)
at org.robolectric.android.controller.ActivityController.of(ActivityController.java:25)
at org.robolectric.Robolectric.buildActivity(Robolectric.java:97)
at org.robolectric.Robolectric.buildActivity(Robolectric.java:93)
at com.helmet91.currencyconverter.repositories.SettingsRepositoryTest.createDb(SettingsRepositoryTest.kt:29)
Действительно ли невозможно протестировать что-либо, включающее компоненты жизненного цикла?