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 by
Lukasz 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