一、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