Issue
I have an Instrument test that has four match statements in it. There is one of the four statements that fails when ran with the other three, but passes if it runs by itself.
here is the test that fails
@Test
fun displayTypeFilteredPokemon(){
// When - PokemonList fragment launch and filtered by specific type
launchActivity()
onView(withId(R.id.genAllButton)).perform(click())
// Perform click action to do the filter on specific type
onView(withId(R.id.menu_filter)).perform(click())
onView(withText(R.string.label_type_electric)).perform(click())
// Then - Verify the list is filtered by the selected type
onView(withId(R.id.pokemon_list)).check(RecyclerViewItemCountAssertion(3))
onView(withText("Magnemite")).check(matches(isDisplayed()))
onView(withText("Jolteon")).check(matches(isDisplayed()))
onView(withText("Emolga")).check(matches(isDisplayed()))
}
here is the code for launch activity:
private fun launchActivity(): ActivityScenario<PokemonListActivity>? {
val scenario = launch(PokemonListActivity::class.java)
scenario.onActivity {
val intent = Intent()
intent.putExtra("genId",0)
it.intent = intent
}
return scenario
}
And here is the custom matcher code:
class RecyclerViewItemCountAssertion(private val matcher: Int) : ViewAssertion {
override fun check(view: View?, noViewFoundException: NoMatchingViewException?) {
if(noViewFoundException != null){
throw noViewFoundException
}
val recyclerView = view as RecyclerView
val adapter = recyclerView.adapter!!
assertThat(adapter.itemCount, IsEqual(matcher))
}
}
when using this set of matches it passes:
onView(withId(R.id.pokemon_list)).check(RecyclerViewItemCountAssertion(3))
onView(withText("Jolteon")).check(matches(isDisplayed()))
onView(withText("Emolga")).check(matches(isDisplayed()))
or when this set of matches it passes as well:
onView(withText("Magnemite")).check(matches(isDisplayed()))
here is the view being tested:
I am slightly confused because the view clearly has the matching text there. Could it be the resource isn't idling, therefor the test just closes? For example the reason the test with only one matcher passes is due to being fast enough to match before it finishes?
I have thought about introducing EspressoIdlingResource but I have read that introduces difficulties in a code base and I would like to keep it simple for learning purposes.
Another indicator that I think the race condition is an issue is that when I debug the test it passes. When I just run the test it fails.
Edit 1: when running all the test by itself, I have no errors. When running all the tests in the class I get the following error:
androidx.test.espresso.NoMatchingViewException: No views in hierarchy found matching: with id: com.stegner.androiddex:id/menu_filter
Solution
Your approach to writing espresso tests seems wrong.
While writing a UI test, what we want to confirm is the following. "If user interacts clicks button X, swipes the page, writes 500 to this edittext, and clicks button Y, he will be able to see text Z". As you can see, we are testing the app as if we are the end user and by just interacting with the elements we see in the screen.
private fun launchActivity(): ActivityScenario<PokemonListActivity>? {
val scenario = launch(PokemonListActivity::class.java)
scenario.onActivity {
val intent = Intent()
intent.putExtra("genId",0)
it.intent = intent
}
return scenario
}
When you use launchActivity and pass a data with an intent, you disregard what we want to test,end users can't pass data with intents, they just click to a button which triggers our code to pass the data with intents. So a good test, should be from end to end (from launch screen to the screen you want) with mimicking user's movements(click X, click Y, write 500 to Z etc) Now your problem is most likely resulted from using launchActivity in every single one of your tests inside a method, the second test can't launch the Activity (at least it can't launch the activity fast enough) so you get an error in your first assertion.
androidx.test.espresso.NoMatchingViewException: No views in hierarchy found matching: with id: com.stegner.androiddex:id/menu_filter
You should remove launchActivity() from your test methods and define an activity test rule using the first screen your app displays.
@Rule
public ActivityTestRule<MyFirstActivity> activityRule =
new ActivityTestRule<>(MyFirstActivity.class);
When you annotate this class with the annotation Rule, before every test starts it will make sure this activity is loaded and then you can go to the page you want with mimicking user interactions. If you still have problems after applying this solution, please write it as a comment because then your problem will be related to synchronization which requires a different answer.
Answered By - Prethia
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.