使用Espresso过程中遇到的问题

一、android.support.test.espresso.NoMatchingViewException: No views in hierarchy found matching


android.support.test.espresso.NoMatchingViewException: No views in hierarchy found matching: (with text: is "gh" and Child at position 0 in parent (with id: studiotwotwotest.myapplication:id/lay_root and Child at position 0 in parent with id: android:id/content) and is displayed on the screen to the user)



原因:在AdapterView控件中,在子view运行时才会动态填充view。所以如果布局中有AdapterView(例如ListView,GridView,or Spinner),并且屏幕初始化时并未加载到屏幕里,方法onView()将无效。你需要调用onData()方法来进行控件的查找。



过程:

(一)布局中没有ListView

目的:测试AdapterView之外的控件(测试以editText为id,并且文本为gh的EditText是否存在)

1.activity_main.xml中的代码,EditText中text为空

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/lay_root"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
<EditText
    android:layout_width="100dp"
    android:layout_height="100dp"
    android:text=""
    android:id="@+id/editText"
    tools:layout_constraintTop_creator="1"
    tools:layout_constraintRight_creator="1"
    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:text="TextView"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:id="@+id/textView"
        tools:layout_constraintTop_creator="1"
        android:layout_marginStart="16dp"
        android:layout_marginTop="7dp"
        tools:layout_constraintLeft_creator="1"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        android:layout_marginLeft="16dp" />


</android.support.constraint.ConstraintLayout>

布局预览图(左边一个TextView,右边一个EditText)



现在执行Record Espresso Test,界面中输入的内容



选择exist


现在修改布局文件,给EditText赋值gh,运行生成的测试文件

修改后的main_activity.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/lay_root"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
<EditText
    android:layout_width="100dp"
    android:layout_height="100dp"
    android:text="gh"
    android:id="@+id/editText"
    tools:layout_constraintTop_creator="1"
    tools:layout_constraintRight_creator="1"
    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:text="TextView"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:id="@+id/textView"
        tools:layout_constraintTop_creator="1"
        android:layout_marginStart="16dp"
        android:layout_marginTop="7dp"
        tools:layout_constraintLeft_creator="1"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        android:layout_marginLeft="16dp" />


</android.support.constraint.ConstraintLayout>

生成的测试文件MainActivityTest3中的内容

package studiotwotwotest.myapplication;


import android.support.test.espresso.ViewInteraction;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.LargeTest;

import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;

import static android.support.test.espresso.Espresso.onView;
import static android.support.test.espresso.action.ViewActions.click;
import static android.support.test.espresso.action.ViewActions.closeSoftKeyboard;
import static android.support.test.espresso.action.ViewActions.replaceText;
import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
import static android.support.test.espresso.matcher.ViewMatchers.withId;
import static android.support.test.espresso.matcher.ViewMatchers.withParent;
import static org.hamcrest.Matchers.allOf;

@LargeTest
@RunWith(AndroidJUnit4.class)
public class MainActivityTest3 {

    @Rule
    public ActivityTestRule<MainActivity> mActivityTestRule = new ActivityTestRule<>(MainActivity.class);

    @Test
    public void mainActivityTest3() {
        ViewInteraction editText = onView(
                allOf(withId(R.id.editText),
                        withParent(allOf(withId(R.id.lay_root),
                                withParent(withId(android.R.id.content)))),
                        isDisplayed()));
        editText.perform(click());

        ViewInteraction editText2 = onView(
                allOf(withId(R.id.editText),
                        withParent(allOf(withId(R.id.lay_root),
                                withParent(withId(android.R.id.content)))),
                        isDisplayed()));
        editText2.perform(replaceText("gh"), closeSoftKeyboard());

    }

}

运行结果可以看到一切正常:




(二)布局中有ListView

目的:测试AdapterView(本文中测试的是ListView)

activity_main.xml中的内容,布局中含有一个ListView,高度是固定值200dp

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/lay_root"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
<EditText
    android:layout_width="100dp"
    android:layout_height="200dp"
    android:text=""
    android:id="@+id/editText"
    tools:layout_constraintTop_creator="1"
    tools:layout_constraintRight_creator="1"
    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:text="TextView"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:id="@+id/textView"
        tools:layout_constraintTop_creator="1"
        android:layout_marginStart="16dp"
        android:layout_marginTop="7dp"
        tools:layout_constraintLeft_creator="1"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        android:layout_marginLeft="16dp" />

    <ListView
        android:id="@+id/lv_listview"
        android:layout_width="150dp"
        android:layout_height="200dp"
        tools:layout_constraintTop_creator="1"
        android:layout_marginTop="251dp"
        tools:layout_constraintLeft_creator="1"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>


手机界面


1.点击listview条目中的界面可见的button,并且也选择Exists


生成的测试文件

package studiotwotwotest.myapplication;


import android.support.test.espresso.ViewInteraction;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.LargeTest;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewParent;

import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.hamcrest.TypeSafeMatcher;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;

import static android.support.test.espresso.Espresso.onView;
import static android.support.test.espresso.Espresso.pressBack;
import static android.support.test.espresso.action.ViewActions.click;
import static android.support.test.espresso.assertion.ViewAssertions.matches;
import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
import static android.support.test.espresso.matcher.ViewMatchers.withId;
import static android.support.test.espresso.matcher.ViewMatchers.withParent;
import static android.support.test.espresso.matcher.ViewMatchers.withText;
import static org.hamcrest.Matchers.allOf;

@LargeTest
@RunWith(AndroidJUnit4.class)
public class MainActivityTest3 {

    @Rule
    public ActivityTestRule<MainActivity> mActivityTestRule = new ActivityTestRule<>(MainActivity.class);

    @Test
    public void mainActivityTest3() {
        //隐藏了虚拟键盘
        pressBack();
<span style="white-space:pre">	</span>//查找listview中第一个button,显示内容为0,并点击
        ViewInteraction button = onView(
                allOf(withId(R.id.bt_button), withText("0"),
                        withParent(childAtPosition(
                                withId(R.id.lv_listview),
                                0)),
                        isDisplayed()));
        button.perform(click());
<span style="white-space:pre">	</span>//查找listview中第四个按钮,显示的内容为3,并点击了一下
        ViewInteraction button2 = onView(
                allOf(withId(R.id.bt_button), withText("3"),
                        withParent(childAtPosition(
                                withId(R.id.lv_listview),
                                3)),
                        isDisplayed()));
        button2.perform(click());
<span style="white-space:pre">	</span>//检测id为bt_btton,显示内容为0的按钮是否存在
        ViewInteraction button3 = onView(
                allOf(withId(R.id.bt_button),
                        childAtPosition(
                                childAtPosition(
                                        withId(R.id.lv_listview),
                                        0),
                                0),
                        isDisplayed()));
        button3.check(matches(isDisplayed()));

    }

    private static Matcher<View> childAtPosition(
            final Matcher<View> parentMatcher, final int position) {

        return new TypeSafeMatcher<View>() {
            @Override
            public void describeTo(Description description) {
                description.appendText("Child at position " + position + " in parent ");
                parentMatcher.describeTo(description);
            }

            @Override
            public boolean matchesSafely(View view) {
                ViewParent parent = view.getParent();
                return parent instanceof ViewGroup && parentMatcher.matches(parent)
                        && view.equals(((ViewGroup) parent).getChildAt(position));
            }
        };
    }
}

此时可以看到运行结果正常:



2.点击界面listview中不可见的条目,如6,或者7、8、9

package studiotwotwotest.myapplication;


import android.support.test.espresso.ViewInteraction;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.LargeTest;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewParent;

import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.hamcrest.TypeSafeMatcher;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;

import static android.support.test.espresso.Espresso.onView;
import static android.support.test.espresso.Espresso.pressBack;
import static android.support.test.espresso.action.ViewActions.click;
import static android.support.test.espresso.assertion.ViewAssertions.matches;
import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
import static android.support.test.espresso.matcher.ViewMatchers.withId;
import static android.support.test.espresso.matcher.ViewMatchers.withParent;
import static android.support.test.espresso.matcher.ViewMatchers.withText;
import static org.hamcrest.Matchers.allOf;

@LargeTest
@RunWith(AndroidJUnit4.class)
public class MainActivityTest3 {

    @Rule
    public ActivityTestRule<MainActivity> mActivityTestRule = new ActivityTestRule<>(MainActivity.class);

    @Test
    public void mainActivityTest3() {
        //隐藏键盘
        pressBack();
<span style="white-space:pre">	</span>//查找第一个button,显示的内容为0,并点击
        ViewInteraction button = onView(
                allOf(withId(R.id.bt_button), withText("0"),
                        withParent(childAtPosition(
                                withId(R.id.lv_listview),
                                0)),
                        isDisplayed()));
        button.perform(click());
<span style="white-space:pre">	</span>//查找第8个button,显示的内容为7,并点击
        ViewInteraction button2 = onView(
                allOf(withId(R.id.bt_button), withText("7"),
                        withParent(childAtPosition(
                                withId(R.id.lv_listview),
                                7)),
                        isDisplayed()));
        button2.perform(click());
<span style="white-space:pre">	</span>//断言第8个按钮,显示内容为7的存在
        ViewInteraction button3 = onView(
                allOf(withId(R.id.bt_button),
                        childAtPosition(
                                childAtPosition(
                                        withId(R.id.lv_listview),
                                        7),
                                7),
                        isDisplayed()));
        button3.check(matches(isDisplayed()));

    }

    private static Matcher<View> childAtPosition(
            final Matcher<View> parentMatcher, final int position) {

        return new TypeSafeMatcher<View>() {
            @Override
            public void describeTo(Description description) {
                description.appendText("Child at position " + position + " in parent ");
                parentMatcher.describeTo(description);
            }

            @Override
            public boolean matchesSafely(View view) {
                ViewParent parent = view.getParent();
                return parent instanceof ViewGroup && parentMatcher.matches(parent)
                        && view.equals(((ViewGroup) parent).getChildAt(position));
            }
        };
    }
}

可以看到运行失败:



解决办法:AdapterView中,如果view在屏幕初始化时不显示,onView()方法将会失效。onData()方法是安全的,出于安全性考虑,可以全部使用该方法。

现在将onView()替换为onData(),运行结果正常

替换后的测试文件

package studiotwotwotest.myapplication;


import android.support.test.espresso.ViewInteraction;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.LargeTest;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewParent;

import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.hamcrest.TypeSafeMatcher;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;

import static android.support.test.espresso.Espresso.onData;
import static android.support.test.espresso.Espresso.onView;
import static android.support.test.espresso.Espresso.pressBack;
import static android.support.test.espresso.action.ViewActions.click;
import static android.support.test.espresso.assertion.ViewAssertions.matches;
import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
import static android.support.test.espresso.matcher.ViewMatchers.withId;
import static android.support.test.espresso.matcher.ViewMatchers.withParent;
import static android.support.test.espresso.matcher.ViewMatchers.withText;
import static org.hamcrest.Matchers.allOf;
import static org.hamcrest.Matchers.hasToString;

@LargeTest
@RunWith(AndroidJUnit4.class)
public class MainActivityTest5 {

    @Rule
    public ActivityTestRule<MainActivity> mActivityTestRule = new ActivityTestRule<>(MainActivity.class);

    @Test
    public void mainActivityTest3() {
        //隐藏键盘
        pressBack();
        
        //查找第一个button,显示的内容为0,并点击
        ViewInteraction button = onData(hasToString("0")).perform(click());
       <pre name="code" class="java">        //查找第8个button,显示的内容为7,并点击
ViewInteraction button1 = onData(hasToString("7")).perform(click());
<span style="white-space:pre">	</span>//断言第8个按钮,显示内容为7的存在
ViewInteraction button2 = onData(hasToString("7")).perform(click()); button2.check(matches(isDisplayed())); }}

 运行结果: 




二、No activities in stage RESUMED. Did you forget to launch the activity. (test.getActivity() or similar)



原因:屏幕锁屏了。

解决方法:测试时保持屏幕处于解锁常亮状态


三、运行测试文件时界面卡住了

布局文件如下,listview的高度设置的是wrap_content,并且距顶部251dp,所以listview位于屏幕底部,完全展开,但是没有在屏幕中完全显示

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/lay_root"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
<EditText
    android:layout_width="100dp"
    android:layout_height="100dp"
    android:text=""
    android:id="@+id/editText"
    tools:layout_constraintTop_creator="1"
    tools:layout_constraintRight_creator="1"
    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:text="TextView"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:id="@+id/textView"
        tools:layout_constraintTop_creator="1"
        android:layout_marginStart="16dp"
        android:layout_marginTop="7dp"
        tools:layout_constraintLeft_creator="1"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        android:layout_marginLeft="16dp" />

    <ListView
        android:id="@+id/lv_listview"
        android:layout_width="362dp"
        android:layout_height="wrap_content"
        tools:layout_constraintTop_creator="1"
        android:layout_marginTop="251dp"
        tools:layout_constraintLeft_creator="1"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>

手机界面为:


测试文件为:

package studiotwotwotest.myapplication;


import android.support.test.espresso.ViewInteraction;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.LargeTest;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewParent;

import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.hamcrest.TypeSafeMatcher;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;

import static android.support.test.espresso.Espresso.onData;
import static android.support.test.espresso.Espresso.onView;
import static android.support.test.espresso.Espresso.pressBack;
import static android.support.test.espresso.action.ViewActions.click;
import static android.support.test.espresso.assertion.ViewAssertions.matches;
import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
import static android.support.test.espresso.matcher.ViewMatchers.withId;
import static android.support.test.espresso.matcher.ViewMatchers.withParent;
import static android.support.test.espresso.matcher.ViewMatchers.withText;
import static org.hamcrest.Matchers.allOf;
import static org.hamcrest.Matchers.hasToString;

@LargeTest
@RunWith(AndroidJUnit4.class)
public class MainActivityTest5 {

    @Rule
    public ActivityTestRule<MainActivity> mActivityTestRule = new ActivityTestRule<>(MainActivity.class);

    @Test
    public void mainActivityTest3() {
      

        
        ViewInteraction button = onData(hasToString("0")).perform(click());
        
        ViewInteraction button1 = onData(hasToString("7")).perform(click());

        
        ViewInteraction button2 = onData(hasToString("7")).perform(click());
        button2.check(matches(isDisplayed()));

    }
}


出现的状况如下,底部左侧的进度条不停地旋转,但是一直不结束:


原因:onData()加载AdapterView中的view时,需要先使view先获取焦点,即加载到屏幕中。如上的测试文件加载了条目7,但是条目7不在屏幕中,又由于listview设置为wrap_content,即listview已经完全展开,并不能移动条目,所以就出现了如上的问题

解决办法:使用onData()方法,在写布局时,需要将listview设置为一个固定的高度,即需要在listview内容长度过长显示不全时可以滑动界面。如设置高度200dp。


修改后的布局:

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/lay_root"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
<EditText
    android:layout_width="100dp"
    android:layout_height="100dp"
    android:text=""
    android:id="@+id/editText"
    tools:layout_constraintTop_creator="1"
    tools:layout_constraintRight_creator="1"
    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:text="TextView"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:id="@+id/textView"
        tools:layout_constraintTop_creator="1"
        android:layout_marginStart="16dp"
        android:layout_marginTop="7dp"
        tools:layout_constraintLeft_creator="1"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        android:layout_marginLeft="16dp" />

    <ListView
        android:id="@+id/lv_listview"
        android:layout_width="150dp"
        android:layout_height="200dp"
        tools:layout_constraintTop_creator="1"
        android:layout_marginTop="251dp"
        tools:layout_constraintLeft_creator="1"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>

修改后的手机界面:



注:参考资料:http://blog.csdn.net/yang786654260/article/details/52670837

    https://developer.android.com/training/testing/ui-testing/espresso-testing.html#run

    http://blog.csdn.net/qq744746842/article/details/50664136

    http://awonwon.blogspot.com/2015/10/hello-espresso.html

    https://google.github.io/android-testing-support-library/docs/espresso/index.html

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值