junit 使用mockk在Kotlin中测试异步函数时的IndexOutOfBoundsExpection

bvpmtnay  于 2023-10-20  发布在  Kotlin
关注(0)|答案(1)|浏览(201)

当测试一个函数时,我遇到了IndexOutOfBoundsException的问题。通常情况下,usersInRangeViewStates的大小应该是2,第一个条目是Resource.Loading,第二个条目是Resource.Success。因为usersInRange(...)是一个异步函数,我必须等待它,所以我添加了runTest{ ... }advanceUntilIdle()。实际上,我认为Asserts的测试会一直等到异步函数完成,但这只是偶尔发生。有没有人看到这个错误,或者你能给我一个更好的解决方案?
代码:

  1. val usersInRange: MutableLiveData<Resource<GETUsers>> = MutableLiveData()
  2. fun getUsersInRange(myUserGeoPoint: GeoPoint, searchRadiusInMeter: Int) = viewModelScope.launch {
  3. usersInRange.postValue(Resource.Loading())
  4. val response = usersInRange(myUserGeoPoint, searchRadiusInMeter)
  5. usersInRange.postValue(Resource.Success(response))
  6. }
  7. private suspend fun usersInRange(myUserGeoPoint: GeoPoint, searchRadiusInMeter: Int)
  8. = withContext(Dispatchers.IO) {
  9. val usersInRangeBuffer = GETUsers()
  10. if(users.value is Resource.Success) {
  11. for(user in (users.value as Resource.Success<GETUsers>).data.users) {
  12. if(user.value.id == myUserID) continue
  13. if(user.value.isInRange(myUserGeoPoint, searchRadiusInMeter)) {
  14. usersInRangeBuffer.users[user.key] = user.value
  15. }
  16. }
  17. }
  18. usersInRangeBuffer
  19. }

测试:

  1. private lateinit var usersInRangeViewStates: MutableList<Resource<GETUsers>>
  2. @Before
  3. fun setUp() {
  4. usersInRangeViewStates = mutableListOf()
  5. viewModel.usersInRange.observeForever {
  6. usersInRangeViewStates.add(it)
  7. }
  8. }
  9. @OptIn(ExperimentalCoroutinesApi::class)
  10. @Test
  11. fun `getUsersInRange() called should return 0 Users from 2 tested Users (plus myUser)`() = runTest {
  12. val myUserGeoPoint = GeoPoint(1.0, 1.0)
  13. val searchRadiusInMeter = 1000
  14. val user01ID = "exampleUser01ID"
  15. val user02ID = "exampleUser02ID"
  16. val user01Location = GETLocation(0.0, 0.0)
  17. val user02Location = GETLocation(0.0, 0.0)
  18. val myUser = GETUser()
  19. val user01 = GETUser(location = user01Location)
  20. val user02 = GETUser(location = user02Location)
  21. val mapUsers = mutableMapOf(myUserID to myUser, user01ID to user01, user02ID to user02)
  22. val users = GETUsers(mapUsers)
  23. val getUsers = Resource.Success(users)
  24. viewModel.users.value = getUsers
  25. viewModel.getUsersInRange(myUserGeoPoint, searchRadiusInMeter)
  26. advanceUntilIdle()
  27. Assert.assertTrue(usersInRangeViewStates[0] is Resource.Loading)
  28. Assert.assertEquals(0, (usersInRangeViewStates[1] as Resource.Success).data.users.size)
  29. Assert.assertFalse((usersInRangeViewStates[1] as Resource.Success).data.users.containsKey(user01ID))
  30. Assert.assertFalse((usersInRangeViewStates[1] as Resource.Success).data.users.containsKey(user02ID))
  31. Assert.assertFalse((usersInRangeViewStates[1] as Resource.Success).data.users.containsKey(myUserID))
  32. }
7y4bm7vi

7y4bm7vi1#

viewModel.getUsersInRangeResource.Success(response)发送到MutableLiveData,然后MutableLiveData请求主线程运行usersInRangeViewStates.add(it)
advanceUntilIdle将等待调度“运行观察者”任务。但是因为观察是在协程之外完成的,它可能不会等待任务实际完成运行。
我认为你可以把测试作为另一件事在主线程上运行。

  1. withContext(Dispatchers.Main) {
  2. Assert.assertTrue(usersInRangeViewStates[0] is Resource.Loading)
  3. Assert.assertEquals(0, (usersInRangeViewStates[1] as Resource.Success).data.users.size)
  4. Assert.assertFalse((usersInRangeViewStates[1] as Resource.Success).data.users.containsKey(user01ID))
  5. Assert.assertFalse((usersInRangeViewStates[1] as Resource.Success).data.users.containsKey(user02ID))
  6. Assert.assertFalse((usersInRangeViewStates[1] as Resource.Success).data.users.containsKey(myUserID))
  7. }

相关问题