lateinit 属性 apiInterface 尚未初始化 kotlin.UninitializedPropertyAccessException:?
lateinit property apiInterface has not been initialized kotlin.UninitializedPropertyAccessException:?
我正在为我的视图模型编写单元测试,当我 运行 测试时出现以下异常
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.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.evaluate(TestWatcher.java:61)
at org.junit.runners.ParentRunner.evaluate(ParentRunner.java:306)
at org.junit.runners.BlockJUnit4ClassRunner.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.run(ParentRunner.java:331)
at org.junit.runners.ParentRunner.schedule(ParentRunner.java:79)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
at org.junit.runners.ParentRunner.access0(ParentRunner.java:66)
at org.junit.runners.ParentRunner.evaluate(ParentRunner.java:293)
at org.junit.runners.ParentRunner.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
低于我的 BBCNewsViewModelTest.kt 我遇到异常的地方
@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)
}
}
在我调用获取新闻功能的界面 class 下方
interface NewsInterface {
@GET(Constants.BBC_URL)
suspend fun getNews(): NewsResponse
}
低于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)
}
}
}
低于我的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)
}
}
}
低于我的NewsResponse.kt
data class NewsResponse(
@SerializedName("articles")
val articles: List<Article>,
@SerializedName("status")
val status: String,
@SerializedName("totalResults")
val totalResults: Int
)
我想知道我到底哪里出错了
正如您的例外所述lateinit property apiInterface has not been initialized
BBCNewsViewModelTest
中的apiInterface
未初始化
并且在您的 setUp()
方法中,您正在初始化 newsRepository = NewsRepository(apiInterface)
而 apiInterface
尚未初始化
您可以在声明时初始化您的 apiInterface
,而无需 lateinit,或者在 setup()
中,或者如果您使用任何依赖注入,您可以进行字段注入
因为你正在使用改造,所以你必须这样初始化
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.build();
NewsInterface service = retrofit.create(NewsInterface.class);
根据异常,您没有初始化 apiInterface
。
正常情况下Retrofit
负责创建NewsInterface
的实例。但是在测试的情况下,您将负责通过实例。为此,您可以创建模拟实现。
class MockNewsInterface: NewsInterface{
suspend fun getNews(): NewsResponse{
return NewsResponse() // Pass dummy implementation
}
}
只需在您的代码中替换它
newsRepository = NewsRepository(MockNewsInterface())
我建议使用 Mockito 或 Mockk.io 库。这将有助于轻松高效地编写测试用例。
我正在为我的视图模型编写单元测试,当我 运行 测试时出现以下异常
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.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.evaluate(TestWatcher.java:61)
at org.junit.runners.ParentRunner.evaluate(ParentRunner.java:306)
at org.junit.runners.BlockJUnit4ClassRunner.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.run(ParentRunner.java:331)
at org.junit.runners.ParentRunner.schedule(ParentRunner.java:79)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
at org.junit.runners.ParentRunner.access0(ParentRunner.java:66)
at org.junit.runners.ParentRunner.evaluate(ParentRunner.java:293)
at org.junit.runners.ParentRunner.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
低于我的 BBCNewsViewModelTest.kt 我遇到异常的地方
@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)
}
}
在我调用获取新闻功能的界面 class 下方
interface NewsInterface {
@GET(Constants.BBC_URL)
suspend fun getNews(): NewsResponse
}
低于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)
}
}
}
低于我的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)
}
}
}
低于我的NewsResponse.kt
data class NewsResponse(
@SerializedName("articles")
val articles: List<Article>,
@SerializedName("status")
val status: String,
@SerializedName("totalResults")
val totalResults: Int
)
我想知道我到底哪里出错了
正如您的例外所述lateinit property apiInterface has not been initialized
BBCNewsViewModelTest
中的apiInterface
未初始化
并且在您的 setUp()
方法中,您正在初始化 newsRepository = NewsRepository(apiInterface)
而 apiInterface
尚未初始化
您可以在声明时初始化您的 apiInterface
,而无需 lateinit,或者在 setup()
中,或者如果您使用任何依赖注入,您可以进行字段注入
因为你正在使用改造,所以你必须这样初始化
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.build();
NewsInterface service = retrofit.create(NewsInterface.class);
根据异常,您没有初始化 apiInterface
。
正常情况下Retrofit
负责创建NewsInterface
的实例。但是在测试的情况下,您将负责通过实例。为此,您可以创建模拟实现。
class MockNewsInterface: NewsInterface{
suspend fun getNews(): NewsResponse{
return NewsResponse() // Pass dummy implementation
}
}
只需在您的代码中替换它
newsRepository = NewsRepository(MockNewsInterface())
我建议使用 Mockito 或 Mockk.io 库。这将有助于轻松高效地编写测试用例。