junit 测试使用Flow的ViewModel

dba5bblo  于 12个月前  发布在  其他
关注(0)|答案(1)|浏览(106)

我有一个ViewModel,它使用Flow从存储库中检索数据。当流程开始时,我将本地' loading ' StateFlow对象设置为true。
我有一个简单的测试,它将一个假的仓库传递给ViewModel。我在我的ViewModel上调用' fetchItems ',它调用我的存储库。

我想Assert加载StateFlow已设置为True,但Assert在流的onStart函数之前执行。
编辑:我知道流程是异步运行的,我想等到流程启动后再进行Assert

然后,一旦我测试了加载状态被设置为真,我也想设置加载状态被设置为假。
我的视图模型:

class MainViewModel @Inject constructor(private val newsInterface: DataRepositoryInterface ) : ViewModel() {
    private val _loading = MutableStateFlow(false)
    val loading: StateFlow<Boolean>
        get() = _loading.asStateFlow()
    
    fun fetchItems(){
        viewModelScope.launch {
            newsInterface.getStories()
                .flowOn(Dispatchers.IO)
                .onStart { _loading.update {true } // Loading has started
                .collect { items ->
                    _loading.update { false }   //Loading has finished
                }
    
        }
    } 
}

我的测试:

@RunWith(JUnit4::class)
class GameUITest {

    lateinit var viewModel: MainViewModel

    @Before
    fun init() {
        viewModel = MainViewModel(FakeNetwork())
    }

    @Test
    fun testViewModel() {
        viewModel.fetchItems()
        assert(viewModel.loading.value == true) // Assertion fails as loading has not been set yet
    }
}

Fake repository:

class FakeNetwork @Inject constructor() : DataRepositoryInterface {
override fun getStories(): Flow<List<Int>> {
    return flow {
        //Do stuff
        emit(listOf(1, 2, 3))
    }
}

}

zmeyuzjn

zmeyuzjn1#

我想出了这个方法。

val loadingStates = mutableListOf<Boolean>()
    // backgroundScope ensures coroutine gets cancelled before the end of the test
    backgroundScope.launch { viewModel.loading.toCollection(loadingStates) }

    viewModel.fetchItems()
    loadingStates.forEachIndexed { index, value ->
        when (index) {
            0 -> Truth.assertThat(value).isFalse()
            1 -> Truth.assertThat(value).isTrue()
            2 -> Truth.assertThat(value).isFalse()
        }
    }

完整文件here
这里发生的事情是,我观察StateFlow发出的值,然后检查发出了什么值。我使用backgroundScope是因为StateFlow上的.toCollection调用永远不会完成,它的协程也永远不会完成-这会导致测试失败。但是backgroundScope可以帮助关闭if for test(:这与通常用于TestSubscriber的Rx测试的方法类似,也可以访问所有发出的值。
也发现Google有点建议同样的方法。实际上,我从那个页面得到了一个背景范围的想法(:

相关问题