该文章记录的是我做日记diary的record espresso UI单元测试过程中所碰到的问题。进行录像单元测试后,有些操作是本身没问题,但是因为Android Studio工具本身没完善record espresso,需要进行代码微调才能达到你想要的效果,下面讲的对应场景的解决方法。
效果图:
效果图.gif什么是单元测试?什么是espresso?这些有很好的讲述了
csdn上的一个博客
官方例子
启动单元测试之前关闭动画
Espresso的同步,如果您在测试设备上允许动画,则不知道如何等待动画完成,可能导致某些测试失败。要关闭测试设备上的动画,请转到“设置” >“ 开发人员选项”,然后关闭“绘图”部分下的所有以下选项:
- 窗口动画比例
- 过渡动画比例
- 动画师持续时间刻度
场景1:文本框按下回车进行系列事件
有个场景是文本框输入某些文字后,按下回车后会生成一个标签出来。
使用record espresso生成的代码如下
ViewInteraction mEditTextRightClick2 = onView(
allOf(withId(R.id.etTag),
childAtPosition(
allOf(withId(R.id.flowLayoutTag),
childAtPosition(
withClassName(is("android.widget.LinearLayout")),
1)),
0),
isDisplayed()));
mEditTextRightClick2.perform(replaceText("qww\n"), closeSoftKeyboard());
会发现\n,因为录像识别出我们确实是按的回车,但我们要的并不是文本框显示回车,而是需要回车之后生成标签,那么我们这里代码则需要调整成这样:
ViewInteraction mEditTextRightClick = onView(
allOf(withId(R.id.etTag),
childAtPosition(
allOf(withId(R.id.flowLayoutTag),
childAtPosition(
withClassName(is("android.widget.LinearLayout")),
1)),
0),
isDisplayed()));
mEditTextRightClick.perform(click());
mEditTextRightClick.perform(replaceText("qwe"), pressKey(KeyEvent.KEYCODE_ENTER));
唯一区别是这段代码
mEditTextRightClick.perform(click());
mEditTextRightClick.perform(replaceText("qwe"), pressKey(KeyEvent.KEYCODE_ENTER));
这段代码意思就是点击该文本框,然后输入qwe文字之后回车。
场景2:因为特殊事件(比如上面回车系列事件)导致点击无效
使用record espresso生成的代码如下:
ViewInteraction appCompatTextView = onView(
allOf(withText("qww"),
childAtPosition(
allOf(withId(R.id.flowLayoutTag),
childAtPosition(
withClassName(is("android.widget.LinearLayout")),
1)),
1),
isDisplayed()));
appCompatTextView.perform(longClick());
这个长按事件是基于上面的生成标签后,并且长按他,但是录像生成的此代码会报错,长按的是flowLayoutTag本身,而不是child,至于这个问题可能是没进入焦点,所以我们就加入perform(click());
来进入焦点,如下代码所示:
ViewInteraction appCompatTextView = onView(
allOf(withText("qww"),
childAtPosition(
allOf(withId(R.id.flowLayoutTag),
childAtPosition(
withClassName(is("android.widget.LinearLayout")),
1)),
1),
isDisplayed()));
appCompatTextView.perform(click());
appCompatTextView.perform(longClick());
场景3:判断是否第一次界面
这个每次record后都会类似于重新安装一次app,也就是会变成第一次运行app,大部分app在第一次运行后都会有“首次广告界面”的,那么就要在代码里面动态的判断是否运行那些广告界面的录制
场景4:类似ViewPager选择事件
报错:
'has parent matching: with id: xxxx matches multiple views in the hierarchy.
google后有很多类似这样的问题,字面上意思是这个xxxxid存在多个视图。
这个场景是ViewPager每一个页面是个ListView,点击ViewPager
生成的代码比较简单,可能是嵌套层数太多,导致record并不无法精确的知道你点击的是哪个控件。
接下来就是看看如何精确获取控件,那么我们就需要在record过程中,点击如下图
image.png 1.先点击该表情 2.再点击Save and Add Another按钮即可
生成代码如下:
ViewInteraction appCompatImageView = onView(
allOf(withId(R.id.imgAddFunctionFace),
childAtPosition(
childAtPosition(
withClassName(is("android.widget.LinearLayout")),
0),
0),
isDisplayed()));
appCompatImageView.perform(click());
场景4.1:
也会出现过基于上面获取控件后,实际上运行还是会报错,找不到此控件,那么这里有个小诀窍,就是在你想找到的控件的同层结构上,随便添加一个控件,例如EditText,录制测试时对它进行文本编辑操作,然后在你生成代码后,将这个生成的EditText控件换成你想获取的控件即可。
场景5:滑动事件
当你滑动后,record是不会为你生成代码的,所以这方面需要我们微调代码,在需要滑动的地方添加以下代码:
// 往右滑动
onView(withId(R.id.viewPager)).perform(swipeRight());
场景5.1:滑动事件不生效
有时候perform(swipeRight())并没有往右边滑动,用perform(swipeLeft())却能往右边滑动。具体原因还找不到,后面找到了再补充
同理,swipeDown()也会存在一样的问题,需要使用swipeUp()
场景6:自制view不会自动生成测试代码
用代替控件方式比较好,因为直接用Add xxx方式,拿到的索引值,在真实测试中是不行的
场景7:一些固定动画自行添加延迟时间
因为即使关闭了动画,但是一些自制自定义view的一些动画延迟还是存在的,所以我们需要自行添加延迟时间,不然会找不到控件。
try {
Thread.sleep(3000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
场景8:recyclerView点击某个position的代码
录制代码生成是不会对recyclerView特殊对待的,需要自己写一个这样的点击代码
recyclerView.perform(RecyclerViewActions.actionOnItemAtPosition(10, click()));
网友评论