I wrote a test as below for a fragment that shows a list of comments
@RunWith(AndroidJUnit4::class)
class CommentListFragmentTest {
@Rule
@JvmField
var instantExecutorRule = InstantTaskExecutorRule()
private lateinit var mockedViewModel: CommentListViewModel
private val mockNavController = mock<NavController>()
private lateinit var commentListFragment: CommentListFragment
@Before
fun setup() {
mockedViewModel = mock(CommentListViewModel::class.java)
val scenario = launchFragmentInContainer(themeResId = R.style.AppTheme) {
CommentListFragment().apply {
commentListFragment = this
viewModelFactory = ViewModelUtil.createFor(mockedViewModel)
this.viewLifecycleOwnerLiveData.observeForever { viewLifecycleOwner ->
if (viewLifecycleOwner != null) {
// The fragment’s view has just been created
Navigation.setViewNavController(this.requireView(), mockNavController)
}
}
}
}
scenario.onFragment { fragment ->
Navigation.setViewNavController(fragment.requireView(),mockNavController )
}
}
@Test
@UiThreadTest
fun loadCommentsList() {
val commentList: MutableList<Comment> = ArrayList()
commentList.add(mock(Comment::class.java))
commentList.add(mock(Comment::class.java))
commentListFragment.render(CommentListUiModel.SetupList(commentList))
Espresso.onView(withId(R.id.progress_bar))
.check(matches(ViewMatchers.withEffectiveVisibility(ViewMatchers.Visibility.GONE)))
Espresso.onView(withId(R.id.recycler_view))
.check(RecyclerViewItemCountAssertion(2))
Espresso.onView(withId(R.id.emptyCommentList))
.check(matches(ViewMatchers.withEffectiveVisibility(ViewMatchers.Visibility.GONE)))
}
}
and I got exception when calling a method of fragment in test method:
java.lang.IllegalStateException: Method cannot be called on the main application thread (on: main)
at androidx.test.internal.util.Checks.checkState(Checks.java:107)
at androidx.test.internal.util.Checks$1.checkNotMainThread(Checks.java:146)
at androidx.test.internal.util.Checks.checkNotMainThread(Checks.java:126)
at androidx.test.core.app.ActivityScenario.launchInternal(ActivityScenario.java:226)
at androidx.test.core.app.ActivityScenario.launch(ActivityScenario.java:209)
at androidx.fragment.app.testing.FragmentScenario.internalLaunch(FragmentScenario.java:299)
at androidx.fragment.app.testing.FragmentScenario.launchInContainer(FragmentScenario.java:282)
at com.beroozresaan.android.ui.productComment.list.CommentListFragmentTest.setup(CommentListFragmentTest.kt:111)
but when I use like below it works:
@Rule
@JvmField
var uiThreadTestRule = UiThreadTestRule()
@Test
fun loadCommentsList() {
uiThreadTestRule.runOnUiThread {
val commentList: MutableList<Comment> = ArrayList()
commentList.add(mock(Comment::class.java))
commentList.add(mock(Comment::class.java))
commentListFragment.render(CommentListUiModel.SetupList(commentList))
}
Espresso.onView(withId(R.id.progress_bar))
.check(matches(ViewMatchers.withEffectiveVisibility(ViewMatchers.Visibility.GONE)))
Espresso.onView(withId(R.id.recycler_view))
.check(RecyclerViewItemCountAssertion(2))
Espresso.onView(withId(R.id.emptyCommentList))
.check(matches(ViewMatchers.withEffectiveVisibility(ViewMatchers.Visibility.GONE)))
}
I want replace runOnUiThread with @UiThreadTest annotation because UiThreadTestRule deprecated, it seems @UiThreadTest not working, what's the problem? did I do something wrong?