Architecture-components-samples: How to wait for postValue() in UI test

Created on 14 Dec 2017  路  2Comments  路  Source: android/architecture-components-samples

I try to follow sample code but look like it not working to me. Can somebody help me check my code what I am wrong?

@RunWith(AndroidJUnit4::class)
class AFragmentTest {

    @Rule
    @JvmField
    val activityRule = ActivityTestRule(MainActivity::class.java, true, true)

    private lateinit var fragment: AFragment
    private val viewModel = mock(AViewModel::class.java)
    private val listener = mock(AFragment.OnInteractionListener::class.java)
    private val liveData = MutableLiveData<Resource<A>>()

    @Before
    fun setUp() {
        fragment = AFragment()
        fragment.viewModel = viewModel
        `when`(viewModel.liveData).thenReturn(liveData)
        fragment.listener = listener
        activityRule.activity.replaceFragment(fragment)
    }

    @Test
    fun aTestSomeThing() {
        val a = A()
        liveData.postValue(Resource.success(a))
        verify(listener)?.onSuccess(a)
    }
}

If add sleep to wait for postValue() it working. But I think we should not do like this.

liveData.postValue(Resource.success(a))
sleep(1000)

Most helpful comment

Here is a solution that is working for me (so far!) after browsing the source for this test suite.

  1. Make sure the Architecture Components test dependency is installed: androidTestImplementation "androidx.arch.core:core-testing:2.0.0"
  2. In your test class, add the following test rule: @get:Rule val countingTaskExecutorRule = CountingTaskExecutorRule()
  3. Anytime that you call liveData.postValue(), call: countingTaskExecutorRule.drainTasks(3, TimeUnit.SECONDS) (adjust the timeout to your liking) to wait for the tasks to all complete.

Your test class above would look like this:

@RunWith(AndroidJUnit4::class)
class AFragmentTest {

    @Rule
    @JvmField
    val activityRule = ActivityTestRule(MainActivity::class.java, true, true)

    @Rule
    @JvmField 
    val countingTaskExecutorRule = CountingTaskExecutorRule()

    private lateinit var fragment: AFragment
    private val viewModel = mock(AViewModel::class.java)
    private val listener = mock(AFragment.OnInteractionListener::class.java)
    private val liveData = MutableLiveData<Resource<A>>()

    @Before
    fun setUp() {
        fragment = AFragment()
        fragment.viewModel = viewModel
        `when`(viewModel.liveData).thenReturn(liveData)
        fragment.listener = listener
        activityRule.activity.replaceFragment(fragment)
    }

    @Test
    fun aTestSomeThing() {
        val a = A()
        liveData.postValue(Resource.success(a))
        countingTaskExecutorRule.drainTasks(3, TimeUnit.SECONDS)
        verify(listener)?.onSuccess(a)
    }
}

I found this solution from browsing this repo and found this test.

All 2 comments

Here is a solution that is working for me (so far!) after browsing the source for this test suite.

  1. Make sure the Architecture Components test dependency is installed: androidTestImplementation "androidx.arch.core:core-testing:2.0.0"
  2. In your test class, add the following test rule: @get:Rule val countingTaskExecutorRule = CountingTaskExecutorRule()
  3. Anytime that you call liveData.postValue(), call: countingTaskExecutorRule.drainTasks(3, TimeUnit.SECONDS) (adjust the timeout to your liking) to wait for the tasks to all complete.

Your test class above would look like this:

@RunWith(AndroidJUnit4::class)
class AFragmentTest {

    @Rule
    @JvmField
    val activityRule = ActivityTestRule(MainActivity::class.java, true, true)

    @Rule
    @JvmField 
    val countingTaskExecutorRule = CountingTaskExecutorRule()

    private lateinit var fragment: AFragment
    private val viewModel = mock(AViewModel::class.java)
    private val listener = mock(AFragment.OnInteractionListener::class.java)
    private val liveData = MutableLiveData<Resource<A>>()

    @Before
    fun setUp() {
        fragment = AFragment()
        fragment.viewModel = viewModel
        `when`(viewModel.liveData).thenReturn(liveData)
        fragment.listener = listener
        activityRule.activity.replaceFragment(fragment)
    }

    @Test
    fun aTestSomeThing() {
        val a = A()
        liveData.postValue(Resource.success(a))
        countingTaskExecutorRule.drainTasks(3, TimeUnit.SECONDS)
        verify(listener)?.onSuccess(a)
    }
}

I found this solution from browsing this repo and found this test.

CountingTaskExecutorRule is the correct class to use, yep.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

easyandroid-cc picture easyandroid-cc  路  13Comments

lucandr picture lucandr  路  15Comments

wafer-li picture wafer-li  路  14Comments

faris-jameel picture faris-jameel  路  28Comments

iammert picture iammert  路  14Comments