测试LiveData和协同程序时出现线程问题

时间:2019-08-25 05:05:30

标签: android unit-testing android-livedata kotlin-coroutines

在测试过程中出现了一个奇怪的错误,我无法弄清。

这是我的视图模型-

class MediaViewModel constructor(repository: Repository) : ViewModel() {

    private var _media : LiveData<List<Media>> = repository.loadMediaForFolder(...)
    private val media = MediatorLiveData<List<Media>>()
    private var _sortOptions = Pair(MediaSortType.DATE_MODIFIED, false)

    init {
        media.addSource(_media) {
            viewModelScope.launch {
                media.value = sortMedia(it)
            }
        }
    }

    fun getMediaList(): LiveData<List<Media>> {
        return media
    }

    fun rearrangeMedia(sortType: MediaSortType, sortAsc: Boolean) {
        viewModelScope.launch {
            val pair = Pair(sortType, sortAsc)
            if (_sortOptions != pair) {
                _sortOptions = pair

                _media.value?.let { media.value = sortMedia(it) }
            }
        }
    }

    private suspend fun sortMedia(mediaList: List<Media>)
            : List<Media> {
        return withContext(Dispatchers.Default) {
            when (_sortOptions.second) {
                true -> when (_sortOptions.first) {
                    MediaSortType.NAME -> mediaList.sortedBy { it.mediaName }
                    MediaSortType.SIZE -> mediaList.sortedBy { it.size }
                    ...
                }
                false -> when (_sortOptions.first) {
                    MediaSortType.NAME -> mediaList.sortedByDescending { it.mediaName }
                    MediaSortType.SIZE -> mediaList.sortedByDescending { it.size }
                    ...
                }
            }
        }
    }
}

非常简单的viewmodel,它在后台对_media中的存储库数据进行排序,然后更新中介者livedata media,它作为普通livedata公开给视图。

为此的测试类-

@ExperimentalCoroutinesApi
class MediaViewModelTest {

    private val folderDao = Mockito.mock(FolderDao::class.java)

    private lateinit var mediaViewModel: MediaViewModel

    private lateinit var repository: Repository

    @ExperimentalCoroutinesApi
    @get:Rule
    var mainCoroutineRule = MainCoroutineRule()

    @get:Rule
    val instantTaskExecutorRule = InstantTaskExecutorRule()

    @Before
    fun setupViewModel() {
        val mediaList = ...
        `when`(folderDao...).thenReturn(MutableLiveData(mediaList))

        repository = Repository(folderDao)
        mediaViewModel = MediaViewModel(repository)
    }

    @Test
    fun getMedia_sortBySizeDesc() {
        mediaViewModel.rearrangeMedia(MediaSortType.SIZE, false)

        val mediaListVm = LiveDataTestUtil.getValue(mediaViewModel.getMediaList())
        Truth.assertThat(mediaListVm).isInOrder { o1, o2 ->
            (o2 as Media).size.compareTo((o1 as Media).size)
        }
    }

    @Test
    fun getMedia_sortByNameAsc_thenByWidthDesc_thenByDateAsc() {
        mediaViewModel.rearrangeMedia(MediaSortType.NAME, true)

        var mediaListVm = LiveDataTestUtil.getValue(mediaViewModel.getMediaList())
        Truth.assertThat(mediaListVm).isInOrder { o1, o2 ->
            (o1 as Media).mediaName.compareTo((o2 as Media).mediaName)
        }

        mediaViewModel.rearrangeMedia(MediaSortType.WIDTH, false)

        mediaListVm = LiveDataTestUtil.getValue(mediaViewModel.getMediaList())
        Truth.assertThat(mediaListVm).isInOrder { o1, o2 ->
            (o2 as Media).width.compareTo((o1 as Media).width)
        }

        mediaViewModel.rearrangeMedia(MediaSortType.DATE_MODIFIED, true)

        mediaListVm = LiveDataTestUtil.getValue(mediaViewModel.getMediaList())
        Truth.assertThat(mediaListVm).isInOrder { o1, o2 ->
            (o1 as Media).dateModified.compareTo((o2 as Media).dateModified)
        }
    }
}

LiveDataTestUtil已摘自here

我正在尝试测试我的VM是否正确地对数据进行排序,为此,我进行了两项测试-一个仅执行单个排序,另一个执行一系列排序,一个又一个。

问题是,第一个测试成功完成,但是第二个尝试第二个断言时失败,即由于某种原因,数据未能按宽度排序。但是,如果我以调试模式运行并逐步进行,则测试将成功完成。另外,我发现我可以做一个最终断言,但是中间的断言会失败。这样行得通-

   mediaViewModel.rearrangeMedia(MediaSortType.NAME, true)
   var media = LiveDataTestUtil.getValue(mediaViewModel.getMediaList())

   mediaViewModel.rearrangeMedia(MediaSortType.WIDTH, false)

   mediaViewModel.rearrangeMedia(MediaSortType.DATE_MODIFIED, true)
   Truth.assertThat(media).isInOrder { o1, o2 ->
       (o1 as Media).dateModified.compareTo((o2 as Media).dateModified)
   }

但这不是-

    mediaViewModel.rearrangeMedia(MediaSortType.NAME, true)
    val media = LiveDataTestUtil.getValue(mediaViewModel.getMediaList())
    Truth.assertThat(media).isInOrder { o1, o2 ->
        (o1 as Media).mediaName.compareTo((o2 as Media).mediaName)
    }

    mediaViewModel.rearrangeMedia(MediaSortType.WIDTH, false)
    Truth.assertThat(media).isInOrder { o1, o2 ->                // Fails
        (o2 as Media).width.compareTo((o1 as Media).width)
    }

    mediaViewModel.rearrangeMedia(MediaSortType.DATE_MODIFIED, true)
    Truth.assertThat(media).isInOrder { o1, o2 ->
        (o1 as Media).dateModified.compareTo((o2 as Media).dateModified)
    }

这通过了,但有时也失败了,这意味着存在比赛条件-

    mediaViewModel.rearrangeMedia(MediaSortType.NAME, true)
    Truth.assertThat(getValue(mediaViewModel.getMediaList())).isInOrder { o1, o2 ->
        (o1 as CachedMedia).mediaName.compareTo((o2 as CachedMedia).mediaName)
    }

    mediaViewModel.rearrangeMedia(MediaSortType.WIDTH, false)

    mediaViewModel.rearrangeMedia(MediaSortType.DATE_MODIFIED, true)
    Truth.assertThat(getValue(mediaViewModel.getMediaList())).isInOrder { o1, o2 ->
        (o1 as CachedMedia).dateModified.compareTo((o2 as CachedMedia).dateModified)
    }

这是怎么回事?

0 个答案:

没有答案