junit Espresso UI测试,无法检查加载状态,如何使用实时数据和视图模型测试UI?

vyu0f0g1  于 2022-11-11  发布在  其他
关注(0)|答案(1)|浏览(120)

目前我正在用Espresso实现UI测试/仪器测试,以测试FragmentMovie加载状态和成功状态由于有多个测试库和其他东西,我测试仪器必须包含hilt弹射
UI测试场景:
1.加载状态时,检查我的加载进度条并显示文本加载
1.当处于成功状态时,隐藏正在加载,并显示回收视图
1.已完成

问题

运行测试时跳过Loading state@Test将在ViewModel postValue Success状态后运行。因此,我无法在加载状态时进行测试。
当我不写onView(withId(R.id.progressBar)).check(matches(isDisplayed()))时,测试通过,但我想在加载状态时进行测试。
可能的修复方法,将delay(10000)添加到我的视图模型中,这将延长加载状态的持续时间,但是,我的测试仍处于等待成功状态。
目前我没有使用IdlingResource,因为它不能解决我的问题,
实际场景:
1.片段运行,
1.视图模型提取数据,
1.视图模型加载,
1.查看模型成功,
1.片段测试运行,

  1. viewAssert失败,
    预期值:
    1.片段运行,
    1.视图模型提取数据,
    1.视图模型加载,
  2. FragmentTest检查进度条,
    1.查看模型成功,
    1.碎片测试检查回收视图,
    1.已完成
    为什么?怎么做?

代码

片段影片中的观察者

private val viewModel: MovieViewModel by viewModels()

   [...]

 viewModel.movie.observe(viewLifecycleOwner, {
            Log.d(TAG, "viewModelgetMovie: ${it.status}")
            when (it.status) {
                Status.LOADING -> {
                    Toast.makeText(requireContext(), "loading..", Toast.LENGTH_SHORT).show()
                }
                Status.SUCCESS -> {
                    binding.progressBar.visibility = View.GONE
                    binding.txLoading.visibility = View.GONE
                    if (it.data != null) {
                        list.addAll(it.data)
                        movieAdapter.notifyDataSetChanged()
                    }
                }
                Status.ERROR -> {
                    binding.progressBar.visibility = View.VISIBLE
                    binding.txLoading.text = it.message
                    Toast.makeText(requireContext(), "${it.message}", Toast.LENGTH_SHORT).show()
                }
            }
        })

视图模型

@HiltViewModel
class MovieViewModel @Inject constructor(
    private val repository: MovieRepository,
    private val dispatcher: CoroutineDispatcher
) : ViewModel() {

    // new code
    private val moviePost = MutableLiveData<ResourceHelper<ArrayList<MovieData>>>()

    val movie: LiveData<ResourceHelper<ArrayList<MovieData>>>
        get() = moviePost

    init {
        fetchMovie()
    }

    private fun fetchMovie() {
        viewModelScope.launch(dispatcher) {
            moviePost.postValue(ResourceHelper.loading(null))
            repository.getMovie(1).let { movie ->
                moviePost.postValue(movie)
            }
        }
    }

}

影片片段测试

package com.unlink.moviecatalogue6.ui.movie

import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
import androidx.test.espresso.matcher.ViewMatchers.withId
import androidx.test.ext.junit.rules.ActivityScenarioRule
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.LargeTest
import com.unlink.moviecatalogue6.MainActivity
import com.unlink.moviecatalogue6.R
import dagger.hilt.android.testing.HiltAndroidRule
import dagger.hilt.android.testing.HiltAndroidTest
import org.junit.After
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith

@HiltAndroidTest
@RunWith(AndroidJUnit4::class)
@LargeTest
class MovieFragmentTest {
    @get:Rule(order = 0)
    var hiltRule = HiltAndroidRule(this)

    @get:Rule(order = 1)
    var activityRule = ActivityScenarioRule(MainActivity::class.java)

    @Before
    fun setUp() {
        hiltRule.inject()
    }

    @After
    fun tearDown() {

    }

    @Test
    fun happyPath() {
        onView(withId(R.id.progressBar)).check(matches(isDisplayed())) // error
        // how can i test on loading?
        onView(withId(R.id.recycleMovie)).check(matches(isDisplayed()))
    }
}

错误

androidx.test.espresso.base.DefaultFailureHandler$AssertionFailedWithCauseError: 'is displayed on the screen to the user' doesn't match the selected view.
Expected: is displayed on the screen to the user
Got: "ProgressBar{id=2131231016, res-name=progressBar, visibility=GONE, width=1080, height=44, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=true, is-selected=false, layout-params=androidx.constraintlayout.widget.ConstraintLayout$LayoutParams@a455ee2, tag=null, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=0.0}"

显示错误是因为我的进度条消失了。因为我的测试检查成功状态后的进度条。

屏幕截图

正在加载状态,但我的测试未运行@Test
loading state
成功状态,然后@测试开始
success state
导致错误视图已消失
error
如有任何答复,我们将不胜感激。

qgelzfjb

qgelzfjb1#

我认为这样做的一个方法是在加载之前在测试中使用testDispatcher暂停调度程序,然后手动恢复它。

private val testDispatcher = TestCoroutineDispatcher()

@Test
fun happyPath() {
    testDispatcher.pauseDispather()
    onView(withId(R.id.progressBar)).check(matches(isDisplayed()))
    testDispatcher.resumeDispather()
    onView(withId(R.id.recycleMovie)).check(matches(isDisplayed()))
}

请注意,您应该将加载移出视图模型范围。

moviePost.setValue(ResourceHelper.loading(null))
   viewModelScope.launch(dispatcher) {

        repository.getMovie(1).let { movie ->
            moviePost.postValue(movie)
        }
    }

您可以在此处阅读更多信息:https://developer.android.com/codelabs/advanced-android-kotlin-training-testing-survey#4

相关问题