Lukasz Kalnik
05/26/2023, 7:14 AMobject as a wrapper for Android shared preferences. The preferences are lazily initialized and object properties are delegated to the preferences like this:
object Persistence {
private val prefs by lazy { PreferencesUtil(ContextProvider.context) }
val timestamp by prefs.readOnlyLongPref(R.string.timestamp, 0L)
}
I want to mock the object for tests of another class (where Persistence is a dependency). The problem is, even if I don't reference this object instance in the class under test, but just as a type - i.e. class CartRepository(private val persistence: Persistence), still the test fails with an exception telling that ContextProvider.context has not been initialized.Lukasz Kalnik
05/26/2023, 7:16 AMlazy (actually it's a custom MutableLazy in this case, but the principle is the same) is executed to get the prefs value for the delegate.
Caused by: kotlin.UninitializedPropertyAccessException: lateinit property context has not been initialized
at package_redacted.util.util.ContextProvider$Companion.getContext(ContextProvider.kt:8)
at package_redacted.core.support.Persistence$prefs$2.invoke(Persistence.kt:26)
at package_redacted.core.support.Persistence$prefs$2.invoke(Persistence.kt:26)
at package_redacted.util.util.MutableLazy.getValue(MutableLazy.kt:24)
at package_redacted.core.support.Persistence.getPrefs(Persistence.kt:26)
at package_redacted.core.support.Persistence.<clinit>(Persistence.kt:32)Lukasz Kalnik
05/26/2023, 7:17 AMPersistence type, not the instance itself, still the instance is apparently being created automatically at the same time in clinit.Lukasz Kalnik
05/26/2023, 7:18 AMLukasz Kalnik
05/26/2023, 7:18 AMPersistence behind an interface.lazynoda
05/26/2023, 7:42 AMobject is a singleton created when the app starts, so the Persistence instance is created. Then, checking the Kotlin bytecode, apparently the delegates are also instantiated, so this is calling prefs.readOnly... so prefs is created.
Maybe consider switching to
val timestamp: Long
get() = prefs.readLongPref(......)lazynoda
05/26/2023, 7:44 AMLukasz Kalnik
05/26/2023, 7:45 AMPersistence behind an interface didn't get rid of this error.Lukasz Kalnik
05/26/2023, 7:48 AMget() could probably work, but defeats the convenience of having delegateslazynoda
05/26/2023, 7:50 AMLukasz Kalnik
05/26/2023, 7:50 AMlazynoda
05/26/2023, 7:51 AMget() = doesn't add extra steps / overhead / whatever. In fact, is a more direct access to the data, isn't it?Lukasz Kalnik
05/26/2023, 7:51 AMget() / set() instead of just using byLukasz Kalnik
05/26/2023, 7:52 AMLukasz Kalnik
05/26/2023, 7:52 AMvar properties)Lukasz Kalnik
05/26/2023, 7:53 AMlazynoda
05/26/2023, 7:53 AMobject but a class and then injecting the dependency? If you need a singleton mandatory, let the DI framework to take care of itLukasz Kalnik
05/26/2023, 7:54 AMLukasz Kalnik
05/26/2023, 7:54 AMlazynoda
05/26/2023, 7:55 AMLukasz Kalnik
05/26/2023, 7:56 AMLukasz Kalnik
05/26/2023, 7:56 AM