提问人:Andrey Sedelnikov 提问时间:7/21/2022 最后编辑:Vishal VasaniAndrey Sedelnikov 更新时间:3/26/2023 访问量:453
从单元测试的 Dispatcher 访问 ViewModel MutableState?
Accessing ViewModel MutableState from unit tests' Dispatcher?
问:
我在 ViewModel for Compose 中使用 MutableStates
var desiredDate: MutableState<Date?> = mutableStateOf(null)
此外,我还想接收模型内部状态的变化
snapshotFlow { desiredDate.value }
.onEach { updateConfirmationState() }
.launchIn(viewModelScope)
这作为生产性代码工作得很好。现在我想测试更新一个状态会导致单元测试中另一个状态的更新。我正在使用经典的 MainCoroutineRule 来覆盖 Dispatchers.Main。
现在,每个 snapshotFlow 启动都发生在单独的工作线程中,并且由于 MutableState 未共享,因此所有值均为 null。
应该有一种方法可以以这种方式测试它,对吧?
答:
0赞
Milan
3/26/2023
#1
刚开始测试我的撰写视图模型并遇到了这篇文章。
snapshotFlow 依赖于快照,在应用新快照时会发出新值,而不仅仅是在值更改时发出。在生产代码中,Compose 在后台管理所有快照
因此,这是我测试此视图模型的方式:
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())
}
}
}
请注意,我在 Turbine 内部调用,其中包含有关如何测试共享流的参考。updateAvatar(..)
.test
另外,如果你的项目中还没有类似的东西,下面是一个示例。TestDispatcherRule
评论