Lateinit Property ApiInterface Has Not Been Initialized Kotlin.UninitializedPropertyAccessException:?
I am writing unit test for my viewmodel when I run test I am getting following exception
lateinit property apiInterface has not been initialized
kotlin.UninitializedPropertyAccessException: lateinit property apiInterface has not been initialized
at com.yodgorbek.newstask.presentation.viewmodel.BBCNewsViewModelTest.setUp(BBCNewsViewModelTest.kt:30)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:78)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:567)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
at org.junit.internal.runners.statements.RunBefores.invokeMethod(RunBefores.java:33)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:24)
at org.junit.rules.TestWatcher$1.evaluate(TestWatcher.java:61)
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.runTestClass(JUnitTestClassExecutor.java:110)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.execute(JUnitTestClassExecutor.java:58)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.execute(JUnitTestClassExecutor.java:38)
at org.gradle.api.interna
below my BBCNewsViewModelTest.kt where I am getting an exception
@ExperimentalCoroutinesApi
class BBCNewsViewModelTest{
private var progressObserver = MutableLiveData(false)
private lateinit var apiInterface : NewsInterface
private lateinit var newsRepository: NewsRepository
private lateinit var bbcNewsResponseUseCase: BBCNewsResponseUseCase
private lateinit var viewModel: BBCNewsViewModel
@ExperimentalCoroutinesApi
@get:Rule
var mainCoroutineRule = MainCoroutineRule()
@Before
fun setUp() {
newsRepository = NewsRepository(apiInterface)
bbcNewsResponseUseCase = BBCNewsResponseUseCase(newsRepository)
viewModel = BBCNewsViewModel(bbcNewsResponseUseCase)
}
@Test
fun testsSaveSessionData() = runBlockingTest {
assert(progressObserver.value == viewModel.progress.value)
}
}
below my Interface class where I am calling get news function
interface NewsInterface {
@GET(Constants.BBC_URL)
suspend fun getNews(): NewsResponse
}
below BBCNewsViewModel.kt
import android.os.Build
import androidx.annotation.RequiresApi
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.yodgorbek.newstask.model.NewsResponse
import com.yodgorbek.newstask.domain.use_case.BBCNewsResponseUseCase
import com.yodgorbek.newstask.domain.utils.fold
import com.yodgorbek.newstask.domain.utils.parseDate
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import java.util.Comparator
@RequiresApi(Build.VERSION_CODES.N)
class BBCNewsViewModel(private val useCase: BBCNewsResponseUseCase) : ViewModel() {
var news= MutableLiveData<NewsResponse>()
// Expose to the outside world
// Expose to the outside world
private val error = MutableLiveData<String>()
var progress = MutableLiveData(false)
init{
getNews()
}
@RequiresApi(Build.VERSION_CODES.N)
private fun getNews() {
progress.postValue(true)
viewModelScope.launch(Dispatchers.IO) {
useCase.invoke()
.fold({ newsResponse ->
newsResponse.articles.sortedWith(Comparator.comparing{
it.publishedAt.parseDate()
})
news.postValue(newsResponse)
}, {
error.postValue(it.message)
})
progress.postValue(false)
}
}
}
below my NewsRepository.kt
class NewsRepository(
private val apiInterface:NewsInterface
){
@RequiresApi(Build.VERSION_CODES.N)
suspend fun getNews() : Result<NewsResponse>{
return try {
val response = apiInterface.getNews()
Result.Success(response)
} catch (ex: Exception) {
Result.Error(ex)
}
}
}
below my NewsResponse.kt
data class NewsResponse(
@SerializedName("articles")
val articles: List<Article>,
@SerializedName("status")
val status: String,
@SerializedName("totalResults")
val totalResults: Int
)
I want to know where exactly I am making mistake
Answer
According to the exception, you are not initializing the apiInterface
.
In normal cases Retrofit
is responsible for creating the instance of NewsInterface
. But in case of testing, you will be responsible for passing the instance. For that, you can create the mock implementation.
class MockNewsInterface: NewsInterface{
suspend fun getNews(): NewsResponse{
return NewsResponse() // Pass dummy implementation
}
}
Just replace this in your code
newsRepository = NewsRepository(MockNewsInterface())
I would suggest to use Mockito or Mockk.io library. This will help write the test cases easily and efficiently.
Related Questions
- → should I choose reactjs+f7 or f7+vue.js?
- → Phonegap Android write to sd card
- → Local reference jquery script in nanohttpd (Android)
- → Click to navigate on mobile devices
- → How to allow api access to android or ios app only(laravel)?
- → Access the Camera and CameraRoll on Android using React Native?
- → React native change listening port
- → What is the default unit of style in React Native?
- → Google play market autocomplete icon
- → Warning: Each child in an array or iterator should have a unique "key" prop. Check the render method of `ListView`
- → Using Laravel with Genymotion
- → react native using like web-based ajax function
- → react native pdf View