【问题标题】:viewModel unit test with flow带流程的 viewModel 单元测试
【发布时间】:2021-08-27 15:16:13
【问题描述】:

我正在尝试为我的 viewModel 编写一个单元测试,但我还没有弄清楚如何去做。我正在使用 kotlin flow 和 jetpack compose。在 viewModel 中,该函数更改了 mutableState 列表的值,但是当我在测试中调用它时,我不知道如何检索该值。

下面是我的视图模型、存储库、假存储库和我到目前为止的测试。 我该怎么做?

@HiltViewModel
class MarvelViewModel @Inject constructor(
    private val repository: MarvelRepository
) : ViewModel() {

    val result: MutableState<List<Result>> = mutableStateOf(listOf())

 fun searchCharacter(
        name: String,
        context: Context
    ) {
        viewModelScope.launch {

            val ts = System.currentTimeMillis().toString()
            val md = MessageDigest.getInstance("MD5")
            val input = ts + PRIVATE_KEY + PUBLIC_KEY
            val hash = BigInteger(1, md.digest(input.toByteArray())).toString(16)
            val offset = if (page.value == 1) 0 else PAGE_SIZE * page.value

            repository.searchCharacter(
                name = name,
                limit = PAGE_SIZE,
                offset = offset,
                ts = ts,
                apikey = PUBLIC_KEY,
                hash = hash
            ).onEach { dataState ->
                loading.value = dataState.loading

                dataState.data?.let {
                    Log.d(DEBUG_TAG, it.toString())
                    if (it.data.total > PAGE_SIZE) {
                        val rest = it.data.total % PAGE_SIZE
                        numPages.value = (it.data.total + rest) / PAGE_SIZE
                    }
                    nameSearch.value = textSearch.value
                    result.value = it.data.results

                    pageNumberList.value = (1..numPages.value).toList()

                }

                dataState.error?.let {
                    Toast.makeText(context, "Falha ao carregar", Toast.LENGTH_SHORT).show()

                }
            }.launchIn(viewModelScope)
        }
    }
class MarvelRepositoryImpl @Inject constructor(
    private val retrofitService: RetrofitService
) : MarvelRepository {

    override suspend fun searchCharacter(
        name: String,
        limit: Int,
        offset: Int,
        ts: String,
        apikey: String,
        hash: String
    ): Flow<DataState<Response>> = flow {
        try {
            emit(DataState.loading())

            val response = retrofitService.search(name, limit, offset, ts, apikey, hash)
            emit(DataState.success(response))
        } catch (e: Exception) {
            emit(DataState.error<Response>(e.message ?: "Unknown Error"))
        }

    }
}
class FakeRepositoryImpl : MarvelRepository {

    override suspend fun searchCharacter(
        name: String,
        limit: Int,
        offset: Int,
        ts: String,
        apikey: String,
        hash: String
    ): Flow<DataState<Response>> = flow {
        emit(DataState.loading())
        emit(DataState.success(response))
    }
}

val response = Response(
    data = Data(
        count = 4, limit = 4, offset = 0, results = listOf(
            Result(
                description = "Wounded", id = 1009368, name = "Iron Man",
                thumbnail = Thumbnail(
                    extension = "jpg",
                    path = "http://i.annihil.us/u/prod/marvel/i/mg/9/c0/527bb7b37ff55"
                )
            ),
            Result(
                description = "", id = 1017320, name = "Iron Man (Iron Man 3 - The Official Game)",
                thumbnail = Thumbnail(
                    extension = "jpg",
                    path = "http://i.annihil.us/u/prod/marvel/i/mg/9/03/5239c1408c936"
                )
            ),
            Result(
                description = "", id = 1017294, name = "Iron Man (LEGO Marvel Super Heroes)",
                thumbnail = Thumbnail(
                    extension = "jpg",
                    path = "http://i.annihil.us/u/prod/marvel/i/mg/6/90/5239c3cc8a259"
                )
            ),
            Result(
                description = "", id = 1017310, name = "Iron Man (Marvel Heroes)",
                thumbnail = Thumbnail(
                    extension = "jpg",
                    path = "http://i.annihil.us/u/prod/marvel/i/mg/9/40/5239be60a67da"
                )
            )
        ), total = 7
    ), status = "Ok"
)
@ExperimentalCoroutinesApi
class MarvelViewModelTest {

    @get:Rule
    var instantExecutorRule = InstantTaskExecutorRule()

    @get:Rule
    var mainCoroutineRule = MainCoroutineRule()

    val context = mock(Context::class.java)

    private lateinit var viewModel: MarvelViewModel

    private lateinit var repository: FakeRepositoryImpl

    @Before
    fun setup(){
        repository = FakeRepositoryImpl()
        viewModel = MarvelViewModel(repository)
    }

    @Test
    fun `should return a flow of response`() = runBlockingTest {

        viewModel.searchCharacter("iron man", context)
        
    }
}

【问题讨论】:

  • 你的测试完成了吗?

标签: android unit-testing kotlin android-jetpack-compose


【解决方案1】:

coroutineRule.runBlockingTest 阻塞流直到完成 FakeRepositoryImpl

你可以使用

@Test
    fun success() = coroutineRule.runBlockingTest {
        //when
        viewModel.searchCharacter("iron man", context)
        //verify
        assertEquals(response.data.results, searchViewModel.result)
    }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多