Espresso: Why don't spinners close after selec

2019-02-19 13:26发布

问题:

I have a question about selecting items in Spinners with Espresso. Or to be more exact: The selection works, but after that the view assertions fail because the spinner is still open.

Let's say I have a really simple activity that contains a spinner and a textview that shows the selection, like this:

Now, I wrote an Espresso test that selects 'dogs' and verifies the textview is updated accordingly:

@Test
public void selectDogs() throws Exception {
    onData(allOf(is(instanceOf(String.class)), is("dogs")))
            .inAdapterView(withId(R.id.spinner))
            .perform(click());
    onView(withId(R.id.selected)).check(matches(withText("dogs")));
}

That test fails because the onData()...perform(click()); does not close the spinner, it just leaves it open. Verified it via debugging:

The exception is:

android.support.test.espresso.NoMatchingViewException: No views in hierarchy found matching: with id: org.flinc.app:id/selected
If the target view is not part of the view hierarchy, you may need to use Espresso.onData to load it from one of the following AdapterViews:android.widget.ListPopupWindow$DropDownListView{226cb88 VFED.VC.. .F...... 0,0-231,432}

I can (sort of) fix my tests by adding pressBack() after the spinner selection, but to me this can't be the correct solution. Also it makes problems on the emulator, but it seems to run fine on my device. How to correctly select something in the spinner and then close it?

Thanks a lot for helping!

Here is the activity code for reference:

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.test_spinner);

    Spinner spinner = (Spinner) findViewById(R.id.spinner);
    final TextView selected = (TextView) findViewById(R.id.selected);

    final List<String> items = Arrays.asList("cats", "dogs", "unicorns");
    final ArrayAdapter<String> adapter = new ArrayAdapter<>(this, android.R.layout.simple_spinner_item, items);
    adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
    spinner.setAdapter(adapter);
    spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {

        @Override
        public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
            selected.setText(items.get(position));
        }

        @Override
        public void onNothingSelected(AdapterView<?> parent) {
            selected.setText("");
        }

    });
}

回答1:

You have to click on the spinner first, use this code:

@Test
public void selectDogs() throws Exception {
    onView(withId(R.id.spinner)).perform(click());
    onData(allOf(is(instanceOf(String.class)), is("dogs")))
            .perform(click());
    onView(withId(R.id.selected)).check(matches(withText("dogs")));
}