I try to unit-test my presenter. I have method that update mark and when it failed, app shows toast with translated message.
override fun updateMark(cameraId: Int, markId: Int, createData: MarkCreateData, context: Context) {
view?.let {
view?.showOrHideProgressBar(true)
apiManager.updateMark(cameraId, markId, createData)
.subsIoObsMain()
.subscribe({
view?.showOrHideProgressBar(false)
view?.updateMarkSuccess()
}) {
view?.showOrHideProgressBar(false)
view?.showToast(getStringForLayoutByKey("mark_updated_fail"))
}.addTo(compositeDisposable)
}
}
The method giving the translation is contained in LocalData object that use prefs.
object LocalData {
private val prefs: SharedPreferences = App.instance.getSharedPreferences(this.javaClass.simpleName, Context.MODE_PRIVATE)
fun getStringForLayoutByKey(key: String) =
if (getJsonDataServer().getByKeyOrKeySave(key).isNullOrEmpty()) {
getJsonDataClient().getByKeyOrKeySave(key) ?: ""
} else {
getJsonDataServer().getByKeyOrKeySave(key) ?: ""
}
}
Prefs init with App.instance that is companion lateinit var.
class App @Inject constructor(): Application(), LifecycleObserver {
companion object {
@JvmStatic
lateinit var instance: App
@JvmField
var localData: LocalData? = null
}
override fun onCreate() {
ProcessLifecycleOwner.get().lifecycle.addObserver(this)
super.onCreate()
instance = this
localData = LocalData
buildDagger()
}
}
So i try to run my unit test.
@RunWith(MockitoJUnitRunner::class)
class PlayerPresenterTest {
@Rule
@JvmField
val rule = ImmediateSchedulerRule()
@Mock
lateinit var apiManager: NetworkManager
@Mock
lateinit var playerFragment: PlayerContract.View
@Mock
lateinit var context: Context
@Mock
lateinit var unknownError: UnknownHostException
@Mock
lateinit var localData: LocalData
@Mock
lateinit var sharedPreferences: SharedPreferences
@Mock
lateinit var app: App.Companion
@Mock
lateinit var instance: App
//variables
private lateinit var playerPresenter: PlayerPresenter
private lateinit var markCreateData: MarkCreateData
private val errorMarkUpdate = "mark updated fail. try later"
@Before
fun setup() {
MockitoAnnotations.initMocks(this)
MockKAnnotations.init(this, relaxUnitFun = true)
playerPresenter = PlayerPresenter()
playerPresenter.attachView(playerFragment)
playerPresenter.apiManager = apiManager
markCreateData = MarkCreateData()
}
//try update mark and get error
@Test
fun test_failed_update_mark() {
val error = Observable.error<Mark>(unknownError)
whenever(apiManager.updateMark(cameraId.toInt(), markId.toInt(), markCreateData)).thenReturn(error)
mockkObject(App)
every { App } returns app
every { app.instance } returns instance
every { instance.getSharedPreferences(this.javaClass.simpleName, Context.MODE_PRIVATE) } returns sharedPreferences
every { localData.getStringForLayoutByKey("mark_updated_fail") } returns errorMarkUpdate
playerPresenter.updateMark(cameraId.toInt(), markId.toInt(), markCreateData, context)
verify(playerFragment, atLeastOnce()).showToast(errorMarkUpdate)
}
}
and get error "Caused by: kotlin.UninitializedPropertyAccessException: lateinit property instance has not been initialized" that is referenced to LocalData private val prefs initialization. Could smb help me with this? How can i init instance in my unit-test and avoid that error? Or maybe how i have to mock LocalData object without using reference to App.instance?