安卓单元测试: How to mock an object which contains MutableLiveData but only exposes LiveData?

标签 android junit mockito android-livedata mutablelivedata

我有一个存储库类,它使用一个 MutableLiveData 对象,仅作为 LiveData 公开,将异步 Web 查询的结果返回给 ViewModel。然后 ViewModel 使用 Transformation 将结果映射到 View 观察到的另一个 MutableLiveData。

我认为我通过分离关注点遵循了本模块中推荐的架构,但我发现很难为 ViewModel 编写单元测试:

class DataRepository ( private val webservice: DataWebService ) {

    private val _exception = MutableLiveData<Exception?>(null)
    val exception : LiveData<Exception?> get() = _exception

    private val _data = MutableLiveData<List<DataItem>>()

    val data: LiveData<List<DataItem>> = _data

    private val responseListener = Response.Listener<String> {response ->
        try {
            val list = JsonReader(SearchResult.mapping).readObject(response).map {
                    //Data transformation
            }
            _exception.value = null
            _data.value = list
        } catch (ex: Exception) {
            _exception.value = ex
            _data.value = emptyList()
        } 
    }

    fun findData(searchString: String) {
        _data.value = emptyList()
        webservice.findData(searchString, responseListener = responseListener)
    } 
}
class WebServiceDataViewModel (private val repository: DataRepository, app: App) : AndroidViewModel(app)
{

    val dataList: LiveData<List<DataItem>> = Transformations.map(repository.data) {
        _showEmpty.value = it.isEmpty()
        it
    }
    val exception: LiveData<Exception?> get() = repository.exception

    private val _showEmpty = MutableLiveData(true)
    val showEmpty : LiveData<Boolean> = _showEmpty

    private var _reloadOnCreate = true

    var searchString: String? = null
        set(value) {
            field = value
            if (!value.isNullOrBlank()) {
                repository.findData(value)
            }
        }
}

ViewModel 测试类:
@RunWith(JUnit4::class)
class WebServicePodcastViewModelTest {
    @Rule var instantExecutorRule = InstantTaskExecutorRule()

    @Mock lateinit var repository : DataRepository
    @Mock lateinit var app : App

    lateinit var viewModel: WebServiceDataViewModel

    @Mock lateinit var exceptionObserver : Observer<Exception?>
    @Mock lateinit var dataObserver : Observer<List<DataItem>>
    @Mock lateinit var showEmptyObserver : Observer<Boolean>

    @Before
    fun setUp() {
        MockitoAnnotations.initMocks(this)

        viewModel = WebServiceDataViewModel(repository, app)
        viewModel.exception.observeForever(exceptionObserver)
        viewModel.showEmpty.observeForever(showEmptyObserver)
        viewModel.dataList.observeForever(dataObserver)
    }

    @Test
    fun searchForData() {
        //given
        val searchString = "MockSearch"
        //when
        `when`(repository.findData(searchString)).then { /* How to invoke the mock repositories LiveData? */ }
        //then
        //TODO: verify that ViewModel LiveData behaves as expected
    }
}

那么如何调用模拟类的不可变 LiveData 呢?目前我正在尝试使用 Mockito 和 JUnit,但如果设置简单,我对不同的框架持开放态度!

最佳答案

最后我放弃了 Mockito 并使用了 MockK相反,它就像一个魅力!

关于安卓单元测试: How to mock an object which contains MutableLiveData but only exposes LiveData?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61116273/

相关文章:

java - 如何从 Firebase (java) 中检索最后一个 child ?

Java android 多维数组(可能是散列)与字符串和嵌套类

android - 谷歌分析 android 的自动 Activity 跟踪如何工作

java - 如何使用 Java 测试使用 sleep() 的方法?

selenium - 如何使用 Selenium Webdriver 获取所有列表项?

android - SIP Android 应用程序,如何使用服务和 Activity

java - 我的单元测试中出现 NullPointerException

java - 确定两个列表相等而不关心订购 Mockito

java - 如何编写返回类型为void的测试用例readFile方法

Java - 如何测试 Catch block ?