android 从单元测试的Dispatcher访问ViewModel MutableState?

qojgxg4l  于 2023-03-27  发布在  Android
关注(0)|答案(1)|浏览(94)

我正在ViewModel中使用MutableState进行合成

var desiredDate: MutableState<Date?> = mutableStateOf(null)

另外我还想接收模型内部状态的变化

snapshotFlow { desiredDate.value }
            .onEach { updateConfirmationState() }
            .launchIn(viewModelScope)

现在我想测试在单元测试中更新一个状态会导致其他状态的更新。我使用经典的MainCoroutineRule来覆盖Dispatchers.Main。
现在,每个snapshotFlow启动都发生在一个单独的worker中,并且由于MutableState不是共享的,因此所有值都为null。
应该有办法用这种方式来测试吧?

cwdobuhd

cwdobuhd1#

刚开始测试我的compose视图模型,遇到了this文章。
snapshotFlow依赖于快照,当应用新快照时,而不仅仅是当值更改时,会发出新值。
下面是我测试这个视图模型的方法:

class SettingsViewModel @Inject constructor(
    userRepository: UserRepository
) : ViewModel() {
    private val _user = userRepository.getMe()
    private var _selectedAvatar by mutableStateOf<String?>(null)
    val state = combine(
        _user,
        snapshotFlow { _selectedAvatar },
    ) { user, selectedAvatar ->
        SettingsUiState(selectedAvatar ?: user?.avatar)
    }.stateIn(
        scope = viewModelScope,
        started = SharingStarted.WhileSubscribed(2_000),
        initialValue = SettingsUiState()
    )

    fun updateAvatar(imageUrl: String?) {
        _selectedAvatar = imageUrl
    }
}

data class SettingsUiState(
    val avatar: Any? = null
}

在实际测试中:

@OptIn(ExperimentalCoroutinesApi::class)
class SettingsViewModelTest {
    @get:Rule
    val mockkRule = MockKRule(this)

    @get:Rule
    val dispatcherRule = TestDispatcherRule()

    @MockK
    lateinit var userRepository: UserRepository

    lateinit var viewModel: SettingsViewModel

    @Test
    fun `state returns updated SettingsUiState when selectedAvatar updates`() = runTest {
        val selectedAvatar = "http://www.example.com/2.jpg"
        val user = User(1, "John", "http://www.example.com/1.jpg")

        every { userRepository.getMe() } returns flowOf(user)

        viewModel = SettingsViewModel(userRepository)

        viewModel.state.test {
            assertEquals(SettingsUiState(user.avatar), awaitItem())

            withMutableSnapshot { viewModel.updateAvatar(selectedAvatar) }
            assertEquals(SettingsUiState(selectedAvatar), awaitItem())
        }
    }
}

注意,我在.test内部调用updateAvatar(..),涡轮机有一个关于如何测试共享流的参考。
另外,如果您的项目中还没有类似TestDispatcherRule的东西,这里有一个示例。

相关问题