【问题标题】:Junit5 test is failed with mutableStateOf and coroutineJunit5 测试因 mutableStateOf 和协程而失败
【发布时间】:2022-01-18 16:28:56
【问题描述】:

我有一个 ViewModel 类:

@HiltViewModel
class MyViewModel @Inject constructor(
    private val repo: Repo,
) : ViewModel() {

    val id = mutableStateOf(TextFieldValue())

    fun init(token: String?) {
        viewModelScope.launch {
            withContext(Dispatchers.IO) {
                id.value = TextFieldValue(repo.getId(token))
            }
        }
    }

}

我想为init函数写一个测试代码。

下面是我的测试代码:

@ExperimentalCoroutinesApi
@ExtendWith(InstantExecutorExtension::class, CoroutinesTestExtension::class)
class MyViewModelTest {

    @get:Rule
    var coroutineScope = CoroutinesTestExtension()

    @Mock
    private lateinit var repo: Repo

    private lateinit var vm: MyViewModel


    @BeforeEach
    fun setup() {
        MockitoAnnotations.openMocks(this)

        vm = MyViewModel(repo)
    }

    @Nested
    @DisplayName("init() test")
    inner class InitTest {

        private val token = "test-token"

        @Test
        fun initTest() = runTest {
            val id = "test-id"
            `when`(repo.getId(token))
                .thenReturn(id)

            vm.init(token)
            advanceUntilIdle()

            assertEquals(id, vm.id.value.text)
        }
    }

如果我运行此测试代码,它会失败并显示以下消息:

expected:<[test-id]> but was:<[]>
Expected :test-id
Actual   :

我发现了一些东西......

首先,如果我删除withContext(Dispatchers.IO) { } 行,测试通过! 但repo.getId(token) 应该在后台线程上运行。

其次,如果我将id 的类型从MutableStateOf 更改为MutableLiveData,它可以正常工作。 但是id 正在View/Fragment 上使用,例如:

@Composable
fun MyTextInput() {
    OutlinedTextField(
        value = viewModel.id.value,
        onValueChange = { viewModel.id.value = it },
    )
}

所以我无法改变它。

我该如何解决这个问题?

【问题讨论】:

    标签: android kotlin android-jetpack-compose junit5 coroutine


    【解决方案1】:

    在 ViewModel 中不需要 TextFieldValue

    你可以换成字符串测试一下。

    视图模型

    val id = mutableStateOf("")
    fun init(token: String?) {
            viewModelScope.launch {
                withContext(Dispatchers.IO) {
                    id.value = repo.getId(token)
                }
            }
        }
    

    测试

    @Test
        fun success() = coroutineRule.runBlockingTest {
    
            val token = "token"
            val id = "test-id"
            //Given
            coEvery { repo.getId(token) } returns "test-id" 
    
            vm.init(token)
    
            assertEquals(id, vm.id )
        }
    

    【讨论】:

    • coroutineRule 是什么??
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-02-15
    • 1970-01-01
    • 2012-05-27
    • 2019-05-01
    相关资源
    最近更新 更多