如何在Android中使用Junit、Mockito和Kotlin流测试ViewModel

33qvvth1  于 11个月前  发布在  Android
关注(0)|答案(1)|浏览(111)

我尝试使用Junit和Mockito测试ViewModel,得到空指针异常。它返回无法调用流收集器。我想测试的响应来在MpinDataKey,检查所有参数都在MpinDataKey,API调用等.
获取以下异常:
线程“Test worker@coroutine#2”中出现异常java.lang.NullPointerException:无法调用“kotlinx.coroutines.flow.Flow.collect(kotlinx.coroutines.flow.FlowCollector,kotlin.coroutines.Continuation)”从未设置LiveData值。java.util.concurrent.TimeoutException:从未设置LiveData值。atLiveDataUtilTestKt. getOrWaitValueTest(LiveDataUtilTest.kt:38)

data class MpinKeyData( val token: String, val publicKey: String)
sealed class Result<T> { 
class Loading<T>: Result<T>()
data class Success<T>(val data: T): Result<T>()
data class Error<T>(val errorMessage: String): Result<T>() 
}
class LoginViewModel @Inject constructor(private val loginRepository: LoginRepository): ViewModel() {

    private var _mpinKeyResponse = MutableLiveData<Result<MpinKeyData>>()
    val mpinKeyResponse: LiveData<Result<MpinKeyData>>
        get() = _mpinKeyResponse

    
    fun getMpinkey(context: Context) {
        viewModelScope.launch {
            loginRepository.getMpinKey(context).collect() {
                _mpinKeyResponse.postValue(it)
            }
        }
    }
}
class LoginDataSource @Inject constructor() {

suspend fun getMpinKey(context: Context): Result<MpinKeyData> { 
return try { 
val retrofit = RetrofitBuilder.getUnAuthRetrofit(context)
val loginService: LoginService by lazy { retrofit.create(LoginService::class.java) 
  } 
val response = loginService.getMpinKey() ResponseHelper.processResponse(response)
}catch (e: Exception) {
Result.Error(e.message ?: "Exception Found") 
   } 
 } 
}
@VisibleForTesting(otherwise = VisibleForTesting.NONE)
fun <T> LiveData<T>.getOrAwaitValueTest(
    time: Long = 2,
    timeUnit: TimeUnit = TimeUnit.SECONDS,
    afterObserve: () -> Unit = {}
): T {
    var data: T? = null
    val latch = CountDownLatch(1)
    val observer = object : Observer<T> {
        override fun onChanged(value: T) {
            data = value
            latch.countDown()
            this@getOrAwaitValueTest.removeObserver(this)
        }
    }
    this.observeForever(observer)

    try {
        afterObserve.invoke()

        // Don't wait indefinitely if the LiveData is not set.
        if (!latch.await(time, timeUnit)) {
            throw TimeoutException("LiveData value was never set.")
        }

    } finally {
        this.removeObserver(observer)
    }

    @Suppress("UNCHECKED_CAST")
    return data as T
}
class LoginViewModelTest {

    @Mock
    private lateinit var loginRepository: LoginRepository

    @Mock
    private lateinit var loginDataSource: LoginDataSource

    private val testDispatcher = StandardTestDispatcher()

    @get:Rule
    val instantTaskExecutorRule = InstantTaskExecutorRule()

    @ExperimentalCoroutinesApi
    @get:Rule
    val mainDispatcherRule = MainDispatcherRule()

    private val context: Context = mock(Context::class.java)

    @Before
    fun initSetUp(){
        MockitoAnnotations.openMocks(this)
        Dispatchers.setMain(testDispatcher)
    }

    @ExperimentalCoroutinesApi
    @Test
    fun test_beginEnroll_Success() = runTest{
//        Mockito.`when`(loginDataSource.getMpinKey(context)).thenReturn(Result.Success<MpinKeyData>)
        val vmodel = LoginViewModel(loginRepository)
        vmodel.getMpinkey(context)
        testDispatcher.scheduler.advanceUntilIdle()
        val  result = vmodel.mpinKeyResponse.getOrAwaitValueTest()
        Assert.assertEquals(0,result)
    }

    @ExperimentalCoroutinesApi
    @Test
    fun test_beginEnroll_Failure() = runTest{
        Mockito.`when`(loginDataSource.getMpinKey(context)).thenReturn(Result.Error("Something went wrong"))
        val vmodel = LoginViewModel(loginRepository)
        vmodel.getMpinkey(context)
        testDispatcher.scheduler.advanceUntilIdle()
        val  result = vmodel.mpinKeyResponse.getOrAwaitValueTest()
        Assert.assertEquals(1,result is Result.Error)
    }

    @After
    fun tearDown() {
        Dispatchers.resetMain()
    }

}
vjhs03f7

vjhs03f71#

@ExperimentalCoroutinesApi
  @Test
  fun test_beginEnroll_Success() = runTest{
          doReturn(flowOf(Result.Success(data = emptyList<MpinKeyData>()))).`when`(loginRepository).getMpinKey(context)
          loginRepository.getMpinKey(context).test{
              assertEquals(Result.Success(emptyList<List<MpinKeyData>>()), awaitItem())
              cancelAndIgnoreRemainingEvents()
          }
          verify(loginRepository).getMpinKey(context)
  }

  @ExperimentalCoroutinesApi
  @Test
  fun test_beginEnroll_Failure() = runTest{

      val errorMessage = "Something went wrong"

      doReturn(flowOf(Result.Error<MpinKeyData>(errorMessage))).`when`(loginRepository).getMpinKey(context)

      loginRepository.getMpinKey(context).test {
          assertEquals(
              Result.Error<MpinKeyData>(errorMessage),
              awaitItem()
          )
          cancelAndIgnoreRemainingEvents()
      }
      verify(loginRepository).getMpinKey(context)
  }

字符串

相关问题