У меня есть следующий проект в Github: https://github.com/Ali-Rezaei/SuperHero-Coroutines
Я хочу написать unitTest для моего класса viewModel:
@RunWith(MockitoJUnitRunner::class)
class MainViewModelTest {
@get:Rule
var rule: TestRule = InstantTaskExecutorRule()
@Mock
private lateinit var context: Application
@Mock
private lateinit var api: SuperHeroApi
@Mock
private lateinit var dao: HeroDao
private lateinit var repository: SuperHeroRepository
private lateinit var viewModel: MainViewModel
private lateinit var heroes: List<Hero>
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
val localDataSource = SuperHeroLocalDataSource(dao)
val remoteDataSource = SuperHeroRemoteDataSource(context, api)
repository = SuperHeroRepository(localDataSource, remoteDataSource)
viewModel = MainViewModel(repository)
heroes = mutableListOf(
Hero(
1, "Batman",
Powerstats("1", "2", "3", "4", "5"),
Biography("Ali", "Tehran", "first"),
Appearance("male", "Iranian", arrayOf("1.78cm"), arrayOf("84kg"), "black", "black"),
Work("Android", "-"),
Image("url")
)
)
}
@Test
fun loadHeroes() = runBlocking {
`when`(repository.getHeroes(anyString())).thenReturn(Result.Success(heroes))
with(viewModel) {
showHeroes(anyString())
assertFalse(dataLoading.value!!)
assertFalse(isLoadingError.value!!)
assertTrue(errorMsg.value!!.isEmpty())
assertFalse(getHeroes().isEmpty())
assertTrue(getHeroes().size == 1)
}
}
}
Я получаю следующее исключение:
java.lang.NullPointerException
at com.sample.android.superhero.data.source.remote.SuperHeroRemoteDataSource$getHeroes$2.invokeSuspend(SuperHeroRemoteDataSource.kt:25)
at |b|b|b(Coroutine boundary.|b(|b)
at com.sample.android.superhero.data.source.SuperHeroRepository.getHeroes(SuperHeroRepository.kt:21)
at com.sample.android.superhero.MainViewModelTest$loadHeroes$1.invokeSuspend(MainViewModelTest.kt:68)
Caused by: java.lang.NullPointerException
at com.sample.android.superhero.data.source.remote.SuperHeroRemoteDataSource$getHeroes$2.invokeSuspend(SuperHeroRemoteDataSource.kt:25)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(Dispatched.kt:233)
at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:594)
at kotlinx.coroutines.scheduling.CoroutineScheduler.access$runSafely(CoroutineScheduler.kt:60)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:742)
А вот мой класс RemoteDataSource:
@Singleton
class SuperHeroRemoteDataSource @Inject constructor(
private val context: Context,
private val api: SuperHeroApi
) : SuperHeroDataSource {
override suspend fun getHeroes(query: String): Result<List<Hero>> = withContext(Dispatchers.IO) {
try {
val response = api.searchHero(query).await()
if (response.isSuccessful && response.body()?.response == "success") {
Result.Success(response.body()?.wrapper!!)
} else {
Result.Error(DataSourceException(response.body()?.error))
}
} catch (e: SocketTimeoutException) {
Result.Error(
DataSourceException(context.getString(R.string.no_internet_connection))
)
} catch (e: IOException) {
Result.Error(DataSourceException(e.message ?: "unknown error"))
}
}
}
Когда мы используем Rxjava
, мы можем создать Observable так же просто, как:
val observableResponse = Observable.just(SavingsGoalWrapper(listOf(savingsGoal)))
`when`(api.requestSavingGoals()).thenReturn(observableResponse)
Как насчет Deferred
в сопрограммах?Как я могу проверить свой метод:
fun searchHero(@Path("name") name: String): Deferred<Response<HeroWrapper>>