在Kotlin中为ViewModel编写单元测试用例

时间:2019-10-03 19:46:02

标签: android unit-testing android-livedata android-viewmodel mockito-kotlin

我正在使用Junit&Mockito 4对viewModel进行单元测试。

ViewModel类

class MainViewModel(app: Application, private val githubRepo: GithubRepository) :
    BaseViewModel(app) {


    private val _trendingLiveData by lazy { MutableLiveData<Event<DataState<List<TrendingResponse>>>>() }
    val trendingLiveData: LiveData<Event<DataState<List<TrendingResponse>>>> by lazy { _trendingLiveData }

    var loadingState = MutableLiveData<Boolean>()


    fun getTrendingData(language: String?, since: String?) {
        launch {
            loadingState.postValue(true)
            when (val result = githubRepo.getTrendingListAsync(language, since).awaitAndGet()) {
                is Result.Success -> {
                    loadingState.postValue(false)
                    result.body?.let {
                        Event(DataState.Success(it))
                    }.run(_trendingLiveData::postValue)
                }

                is Result.Failure -> {
                    loadingState.postValue(false)
                }
            }
        }
    }

}

Api EndPoinit

interface GithubRepository {

    fun getTrendingListAsync(
        language: String?,
        since: String?
    ): Deferred<Response<List<TrendingResponse>>>
}

ViewModel测试类

@RunWith(JUnit4::class)
class MainViewModelTest {

    @Rule
    @JvmField
    val instantTaskExecutorRule = InstantTaskExecutorRule()

    @Mock
    lateinit var repo: GithubRepository

    @Mock
    lateinit var githubApi: GithubApi

    @Mock
    lateinit var application: TrendingApp
    lateinit var viewModel: MainViewModel

    @Mock
    lateinit var dataObserver: Observer<Event<DataState<List<TrendingResponse>>>>

    @Mock
    lateinit var loadingObserver: Observer<Boolean>

    private val threadContext = newSingleThreadContext("UI thread")
    private val trendingList : List<TrendingResponse> = listOf()


    @Before
    fun setUp() {
        MockitoAnnotations.initMocks(this)
        Dispatchers.setMain(threadContext)
        viewModel = MainViewModel(application, repo)
    }


    @Test
    fun test_TrendingRepo_whenSuccess() {

        //Assemble
        Mockito.`when`(githubApi.getTrendingListAsync("java", "daily"))
            .thenAnswer{ return@thenAnswer trendingList.toDeferred() }

        //Act
        viewModel.trendingLiveData.observeForever(dataObserver)
        viewModel.loadingState.observeForever(loadingObserver)
        viewModel.getTrendingData("java", "daily")

        Thread.sleep(1000)

        //Verify
        verify(loadingObserver).onChanged(true)
        //verify(dataObserver).onChanged(trendingList)
        verify(loadingObserver).onChanged(false)


    }


    @After
    fun tearDown() {
        Dispatchers.resetMain()
        threadContext.close()
    }
}

问题是我的实时数据缠绕在Event<DataState<List<TrendingResponse>>周围,因此我无法获取应为dataObserver的数据以及如何在测试类中验证dataObserver的数据。

事件os开放类,用于处理诸如SingleLiveData之类的事件

DataState是包含SUCCESS&FAILED数据类的密封类

我写的测试用例livedata像LiveData<List<Response>之类。

1 个答案:

答案 0 :(得分:0)

您需要使用Mockito-List<TrendingResponse>包装要返回的Event(DataState.Success(List<TrendingResponse>))trendingList.toDeferred()

@Test
fun test_TrendingRepo_whenSuccess() {

    //Assemble
    Mockito.`when`(githubApi.getTrendingListAsync("java", "daily"))
        .thenAnswer{ return@thenAnswer trendingList.toDeferred() }

    //Act
    viewModel.trendingLiveData.observeForever(dataObserver)
    viewModel.loadingState.observeForever(loadingObserver)
    viewModel.getTrendingData("java", "daily")

    Thread.sleep(1000)

    //Verify
    verify(loadingObserver).onChanged(true)
    //wrap the trendingList inside Event(DataState(YourList))
    verify(dataObserver).onChanged(Event(DataState.Success(trendingList)))
    verify(loadingObserver).onChanged(false)


}