2

I have just started experimenting with the Espresso testing framework for Android and the first thing I wanted to do was click the "Settings" button in an activity's options menu. However, when I try to call openActionBarOverflowOrOptionsMenu(getInstrumentation().getTargetContext()) the test crashes with this exception

android.support.test.espresso.NoMatchingViewException: No views in hierarchy found matching: ((is displayed on the screen to the user and with content description: is "More options") or (is displayed on the screen to the user and with class name: a string ending with "OverflowMenuButton"))

View Hierarchy:
+>DecorView{id=-1, visibility=VISIBLE, width=800, height=1232, has-focus=true, has-focusable=true, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=0.0, child-count=1}
|
+->LinearLayout{id=-1, visibility=VISIBLE, width=800, height=1232, has-focus=true, has-focusable=true, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=0.0, child-count=2}
|
+-->ViewStub{id=16909074, visibility=GONE, width=0, height=0, 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, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=0.0}
|
+-->FrameLayout{id=16908290, res-name=content, visibility=VISIBLE, width=800, height=1207, has-focus=true, has-focusable=true, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=25.0, child-count=1}
|
+--->RelativeLayout{id=-1, visibility=VISIBLE, width=800, height=1207, has-focus=true, has-focusable=true, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=0.0, child-count=9}
|
+---->ImageView{id=2131361813, res-name=main_logo, desc=logo, visibility=VISIBLE, width=768, height=158, 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=false, is-selected=false, root-is-layout-requested=false, has-input-connection=false, x=16.0, y=36.0}
|
+---->Button{id=2131361814, res-name=main_new_button, visibility=INVISIBLE, width=210, height=48, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=true, is-enabled=true, is-focused=false, is-focusable=true, is-layout-requested=false, is-selected=false, root-is-layout-requested=false, has-input-connection=false, x=295.0, y=232.0, text=New forest, input-type=0, ime-target=false, has-links=false}
|
+---->Button{id=2131361815, res-name=main_load_button, visibility=VISIBLE, width=210, height=48, has-focus=true, has-focusable=true, has-window-focus=true, is-clickable=true, is-enabled=true, is-focused=true, is-focusable=true, is-layout-requested=false, is-selected=false, root-is-layout-requested=false, has-input-connection=false, x=295.0, y=310.0, text=Load forest, input-type=0, ime-target=true, has-links=false}
|
+---->Button{id=2131361816, res-name=satform_download_button, visibility=VISIBLE, width=210, height=48, has-focus=false, has-focusable=true, has-window-focus=true, is-clickable=true, is-enabled=true, is-focused=false, is-focusable=true, is-layout-requested=false, is-selected=false, root-is-layout-requested=false, has-input-connection=false, x=295.0, y=388.0, text=Download, input-type=0, ime-target=false, has-links=false}
|
+---->Button{id=2131361817, res-name=main_resume_button, visibility=GONE, width=0, height=0, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=true, is-enabled=true, is-focused=false, is-focusable=true, is-layout-requested=true, is-selected=false, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=0.0, text=Continue, input-type=0, ime-target=false, has-links=false}
|
+---->ToggleButton{id=2131361818, res-name=marking_mode_toggle, visibility=VISIBLE, width=223, height=48, has-focus=false, has-focusable=true, has-window-focus=true, is-clickable=true, is-enabled=true, is-focused=false, is-focusable=true, is-layout-requested=false, is-selected=false, root-is-layout-requested=false, has-input-connection=false, x=288.0, y=466.0, text=Auto Marking RFID mode, input-type=0, ime-target=false, has-links=false, is-checked=false}
|
+---->ProgressBar{id=2131361819, res-name=progress_bar, visibility=GONE, width=0, height=0, 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, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=0.0}
|
+---->TextView{id=2131361820, res-name=progress_text, visibility=GONE, width=0, height=0, 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, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=0.0, text=Please wait…, input-type=0, ime-target=false, has-links=false}
|
+---->TextView{id=2131361821, res-name=version_text, visibility=VISIBLE, width=210, height=25, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=true, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, root-is-layout-requested=false, has-input-connection=false, x=295.0, y=1128.0, text=version:0.7.0, input-type=0, ime-target=false, has-links=false}
|
at dalvik.system.VMStack.getThreadStackTrace(Native Method)
at java.lang.Thread.getStackTrace(Thread.java:579)
at android.support.test.espresso.base.DefaultFailureHandler.getUserFriendlyError(DefaultFailureHandler.java:82)
at android.support.test.espresso.base.DefaultFailureHandler.handle(DefaultFailureHandler.java:53)
at android.support.test.espresso.ViewInteraction.runSynchronouslyOnUiThread(ViewInteraction.java:184)
at android.support.test.espresso.ViewInteraction.doPerform(ViewInteraction.java:115)
at android.support.test.espresso.ViewInteraction.perform(ViewInteraction.java:87)
at android.support.test.espresso.Espresso.openActionBarOverflowOrOptionsMenu(Espresso.java:214)
at com.treemetrics.treedegrees.TestBluetoothPeripheralDialog.openOverflowMenu(TestBluetoothPeripheralDialog.java:28)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at android.support.test.internal.statement.UiThreadStatement.evaluate(UiThreadStatement.java:55)
at android.support.test.rule.ActivityTestRule$ActivityStatement.evaluate(ActivityTestRule.java:257)
at org.junit.rules.RunRules.evaluate(RunRules.java:20)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runners.Suite.runChild(Suite.java:128)
at org.junit.runners.Suite.runChild(Suite.java:27)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
at android.support.test.internal.runner.TestExecutor.execute(TestExecutor.java:54)
at android.support.test.runner.AndroidJUnitRunner.onStart(AndroidJUnitRunner.java:240)
at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:1710)

The options menu is initialised in the activity like this

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    super.onCreateOptionsMenu(menu);
    getMenuInflater().inflate(R.menu.menu_comp_activity, menu);
    this.menu = menu;
    return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    // handle item selection
    switch (item.getItemId()) {
    case R.id.action_rfid:
        toggleRfid(item);
        return true;
    default:
        return super.onOptionsItemSelected(item);
    }
}

@Override
public boolean onPrepareOptionsMenu(Menu menu) {
    super.onPrepareOptionsMenu(menu);
    MainApplication.debugOut(true, 2, TAG, getString(R.string.called_on_prepare_options_menu));
    if (RfidBtService.isRunning){
        menu.findItem(R.id.action_rfid).setTitle(R.string.action_rfid_off);
        menu.findItem(R.id.action_rfid).setIcon(R.drawable.bt_rfid);
    }else{
        menu.findItem(R.id.action_rfid).setTitle(R.string.action_rfid_on);
        menu.findItem(R.id.action_rfid).setIcon(R.drawable.bt_rfid_on);
    }
    return true;
}

and here is the XML for the menu

<menu xmlns:android="http://schemas.android.com/apk/res/android" >

<item
    android:id="@+id/menuitem_saveforest"
    android:onClick="saveForest"
    android:orderInCategory="100"
    android:showAsAction="never"
    android:title="@string/action_save_forest"/>
<item
    android:id="@+id/action_sendforest"
    android:onClick="sendForest"
    android:orderInCategory="100"
    android:showAsAction="never"
    android:title="@string/action_send_forest"/>
<item
    android:id="@+id/action_settings"
    android:onClick="launchSettings"
    android:orderInCategory="100"
    android:showAsAction="never"
    android:title="@string/action_settings"/>
<item
    android:id="@+id/action_saveforest"
    android:icon="@drawable/ic_menu_save"
    android:onClick="saveForest"
    android:showAsAction="always"
    android:title="@string/action_save_forest"/>
<item
    android:id="@+id/action_rfid"
    android:icon="@drawable/bt_rfid_on"
    android:onClick="toggleRfid"
    android:showAsAction="ifRoom"
    android:title="@string/action_rfid_on"/>

</menu>

Here is my test class

@RunWith(AndroidJUnit4.class)
@SmallTest
public class TestBluetoothPeripheralDialog {

  @Rule
  public ActivityTestRule<ForestActivity> mActivityRule
      = new ActivityTestRule<>(ForestActivity.class);

  @Test
  public void openOverflowMenu() {
    // Open the overflow menu OR open the options menu,
    // depending on if the device has a hardware or software overflow menu button.
    openActionBarOverflowOrOptionsMenu(getInstrumentation().getTargetContext());

    // Click the item.
    onView(withText("Settings"))
        .perform(click());
  }

}
Anger Density
  • 332
  • 1
  • 3
  • 17
Adam
  • 2,167
  • 5
  • 19
  • 33

2 Answers2

3

For those who are in the correct activity and still face the error while running the tests, here are a couple of things someone else could try:

  1. Ensure in the developer options of the device that you have Animations off selected in all 3 animations scale - Window/Transition/Animator

  2. Sometimes, the openActionBarOverflowOrOptionsMenu takes some time to load the results. I tend to add a Thread.sleep() for 2 seconds. And it works!

0

I realised my problem. I thought ForestActivity was being launched because it was declared as the generic type in the ActivityTestRule (I still don't know what ActivityTestRule's function is, I've only just started with Espresso and testing on Android in general). So my problem was I was trying to open the overflow menu in the splash screen at the start of the app, as opposed to the ForestActivity.

Adam
  • 2,167
  • 5
  • 19
  • 33