欢迎大家前往腾讯云社区,获取更多腾讯海量技术实践干货哦~


Espresso是一个Google官方提供的Android应用UI自动化测试框架。Google希望,当Android的开发者利用Espresso写完测试用例后,能一边看着测试用例自动执行,一边享受一杯香醇Espresso(浓咖啡)。
Espress有3个特点:

  • 第一个收录在Android Testing Supporting Library底下的测试框架
  • 模拟用户的操作
  • 自动等待,直到UI线程Idle,才会执行测试代码

接下来,将从配置、写用例、运行一步步介绍Espresso的使用。

0. 项目配置

0.1 修改App的build.gradle

  • 在defaultConfig内增加,testInstrumentationRunner “android.support.test.runner.AndroidJUnitRunner”,用来运行脚本
  • 增加packagingOptions,避免编译时候License的冲突
  • 在dependencies中增加相关的引用(androidTestCompile只有在编译测试用例时候才会运行,普通编译不会)
    下面是build.gradle中涉及到Espresso配置的内容
android {
defaultConfig {
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
}
packagingOptions {
exclude 'LICENSE.txt'
}
}
dependencies {
// Espresso 相关的引用
compile 'com.android.support:support-annotations:22.1.1'
androidTestCompile 'com.android.support:support-annotations:22.1.1'
androidTestCompile('com.android.support.test.espresso:espresso-core:2.1'){
exclude group: 'javax.inject'
}
androidTestCompile 'com.android.support.test.espresso:espresso-intents:2.1'
androidTestCompile 'com.android.support.test.espresso:espresso-contrib:2.1'
androidTestCompile 'com.android.support.test:runner:0.2'
}

0.2 添加TestRunner

点击顶栏菜单Run->Edit Configurations,出现如下的窗口后,点击左上角的”+”,选择”Android Tests”;

修改新Configuration的名字,选中App Module,输入Runner,选择”Show chooer dialog”,点击”OK”完成

1. 写测试用例

1.1 三步曲

写UI自动化测试用例,归结起来就是3步:

定位View控件
操作View控件
校验View控件的状态
对应Espresso,就是以下3个方法的调用:

onView(ViewMatcher)
.perform(ViewAction)
.check(ViewAssertion);

其中,onView是用来定位View控件的,perform是操作控件的,check是校验View控件的状态。他们各自都需要再传入对应的参数分别如下:

ViewMatcher,有withId、withText、withClassName等等方法来定位View控件
ViewAction,有click()、longClick()、pressBack()、swipeLeft()等等方法来操作View控件
ViewAssertion,有isEnabled()、isLeftOf()、isChecked()等等方法来校验View控件状态
这里有ViewMatcherViewActionViewAssertion的Cheat Sheet。

1.2 完整测试用例代码

这是一个非常简单的测试用例,通过R.id.button定位控件,对它调用了一下click,最后校验控件是不是enabled状态。这里面有一些注解,@Rule修饰的是被测试的Activity@Test修饰的方法是测试用例。

@RunWith(AndroidJUnit4.class)public class MainActivityTest {    @Rule
public ActivityTestRule mActivityRule = new ActivityTestRule(MainActivity.class); @Test
public void testTextViewDisplay() {
onView(withId(R.id.button))
.perform(click())
.check(matches(isEnabled()));
}
}

1.3 注意

Getting Started With Espresso 2.0这个视频中提到了2个写测试用例时的注意项:

避免Activity的层级跳转,测试用例尽量只在单个Activity内完成。Activity层级跳转越多,越容易出错
强烈不推荐,直接获取View的对象,调用View的方法来模拟用户操作。应该统一使用Espresso提供的方法
测试用例,特别是UI自动化测试用例,应该尽量保持逻辑简单,覆盖关键路径就足矣。因为UI变动是很频繁的,越复杂,维护成本就越高,投入产出比就会自然降低了。

2. 运行用例

  1. 在运行菜单中选择步骤0.2中设置的TestRunner,点击执行
  2. 测试用例模拟用户操作自动运行
  3. 测试用例执行完成,在Android Studio的控制台上,能看到如下的结果输出

其中,看到”Done 3 of 3”标识,一共3个检查点,都检查通过了。如果有检查不通过的话,右上角的绿色能量条会变成红色。

3. 进阶

3.1 onData的使用

对于ListView,如果要操作其中的某一个item,特别是不可见状态的item,是不能通过上述的ViewMatch来定位的。我们都知道ListViewView是复用的,不可见状态的item并没有把内容绘制到View上。Espresso针对AdapterViewListView的父类),提供了onData来支持。

onData(ObjectMatcher)
.DataOptions
.perform(ViewAction)
.check(ViewAssertion);

onData传入的是一个ObjectMather。首先假设ListView的Adapter中的Item的定义如下:

public static class Item {
private final int value;
public Item(int value) {
this.value = value;
}
public String toString() {
return String.valueOf(value);
}
}

下面定义一个withValue()的方法,返回一个BoundedMatcher。而其中的matchesSafely()方法是用来判断match与否的,判断的逻辑实现都放在这里。



public static Matcher<Object> withValue(final int value) {
return new BoundedMatcher<Object,
MainActivity.Item>(MainActivity.Item.class) {
@Override public void describeTo(Description description) {
description.appendText("has value " + value);
}
@Override public boolean matchesSafely(
MainActivity.Item item) {
return item.toString().equals(String.valueOf(value));
}
};
}

有了上面的铺垫,测试用例写起来就水到渠成了。在id是R.id.listAdapterView中找到数据项是27,然后执行click()操作。

@Test
public void clickItem() {
onData(withValue(27))
.inAdapterView(withId(R.id.list))
.perform(click());
//Do the assertion here.
}

最后需要注意的是,onData()并不适用于RecyclerView,因为它不是继承自AdapterView。Espresso提供专门给RecyclerView使用的RecyclerViewActions

@Test
public void clickItem() {
onView(withId(R.id.recycler_view))
.perform(
RecyclerViewActions.actionOnItemAtPosition(27, click()));
}

3.2 Idling Resource的使用

应用开发中很常见的一个场景是,点击某个按钮,发起网络请求,等请求回来后解析数据,更新界面。Espresso针对这种测试场景,提供了原生的支持。
假设被测Activity初始化后有一个耗时的数据加载过程,activity.isSyncFinished()方法判断数据加载是否已经完成。代码如下:

@Override
protected void onCreate(Bundle savedInstanceState) {
//模拟耗时的数据加载
new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
@Override
public void run() {
mIsSyncFinished = true;
}
}, 5000);
} private volatile boolean mIsSyncFinished = false;
public boolean isSyncFinished() {
return mIsSyncFinished;
}

这种情况,Espresso提供了IdlingResource来保证数据加载完成了才开始执行测试用例代码。首先,需实现IdlingResource接口:

  • getName()方法返回的String是作为注册回调的Key,所以要确保唯一性
  • registerIdleTransitionCallback()的参数ResourceCallback会用做isIdleNow()时候的回调
  • isIdleNow()是否已经处于空闲状态,这里调用activity.isSyncFinished()方法来判断数据加载是否完成
private static class MyIdlingResource implements IdlingResource {
private ResourceCallback mCallback = null;
private MainActivity mActivity; MyIdlingResource(MainActivity activity) {
mActivity = activity;
} @Override
public String getName() {
return "MyIdlingResource";
} @Override
public void registerIdleTransitionCallback(ResourceCallback callback) {
mCallback = callback;
} @Override
public boolean isIdleNow() {
boolean isIdle = mActivity != null && mActivity.isSyncFinished();
if (isIdle && mCallback != null) {
mCallback.onTransitionToIdle();
}
return isIdle;
}
}

MyIdlingResource需要在恰当的时机注册和反注册。@Before@After是依照JUnit4的惯例,分别在用例执行之前和之后去注册和反注册。那么,如下测试用例执行的过程是:

  1. 测试用例启动,注册MyIdlingResource
  2. 启动被测Activity
  3. Activity初始化,启动数据加载过程
  4. Activity数据加载完成,执行测试用例方法testTextViewDisplay()
  5. 测试用例结束,反注册MyIdlingResource
    可见,IdlingResource能够保证流转到Idle状态,才会执行测试代码:
@Test
public void testTextViewDisplay() {
onView(withText("Show SnackBar")).check(ViewAssertions.matches(isDisplayed()));
} @Before
public void registerIntentServiceIdlingResource() {
Activity activity = mActivityRule.getActivity();
idlingResource = new MyIdlingResource((MainActivity) activity);
Espresso.registerIdlingResources(idlingResource);
} @After
public void unregisterIntentServiceIdlingResource() {
Espresso.unregisterIdlingResources(idlingResource);
}

3.3. 执行原理

本文开头提到Espresso其中一个特点,无需主动写Sleep等待UI事件的执行和UI的绘制。原因是,Espresso的用例运行过程是只有当UI线程IDLE和UI队列没有需要执行的事件时,Espresso的测试代码才会被执行。使用方无需写Sleep逻辑等待UI绘制完成。以下是Espresso测试用例执行简易的流程图,帮助理解:

写在最后

引用官方介绍的一段话,Espresso的目标受众是开发者。希望更多的团队能够实现Google的期许最大化利用Espresso,把Bug扼杀在摇篮中。

Target Audience
Espresso is targeted at developers, who believe that automated testing is an integral part of the development lifecycle. While it can be used for black-box testing, Espresso’s full power is unlocked by those who are familiar with the codebase under test.

引用

Getting Started With Espresso 2.0:https://www.youtube.com/watch?v=TGU0B4qRlHY
Advanced Android Espresso:https://realm.io/news/chiu-ki-chan-advanced-android-espresso-testing/
Android Espresso 测试框架探究:http://blog.csdn.net/weijianfeng1990912/article/details/51540468
Android自动化测试-AdapterView的测试:https://segmentfault.com/a/1190000004392396
Android单元测试研究与实践:http://tech.meituan.com/Android_unit_test.html

文章来自: QQ音乐技术团队 公众号

相关阅读

网页加速特技之 AMP

表格行与列边框样式处理的原理分析及实战应用

「腾讯云游戏开发者技术沙龙」11月24 日深圳站报名开启 畅谈游戏加速

此文已由作者授权腾讯云技术社区发布,转载请注明原文出处

原文链接:https://cloud.tencent.com/community/article/520289?utm_source=bky

海量技术实践经验,尽在腾讯云社区

Espresso浅析和使用的更多相关文章

  1. SQL Server on Linux 理由浅析

    SQL Server on Linux 理由浅析 今天的爆炸性新闻<SQL Server on Linux>基本上在各大科技媒体上刷屏了 大家看到这个新闻都觉得非常震精,而美股,今天微软开 ...

  2. 【深入浅出jQuery】源码浅析--整体架构

    最近一直在研读 jQuery 源码,初看源码一头雾水毫无头绪,真正静下心来细看写的真是精妙,让你感叹代码之美. 其结构明晰,高内聚.低耦合,兼具优秀的性能与便利的扩展性,在浏览器的兼容性(功能缺陷.渐 ...

  3. 高性能IO模型浅析

    高性能IO模型浅析 服务器端编程经常需要构造高性能的IO模型,常见的IO模型有四种: (1)同步阻塞IO(Blocking IO):即传统的IO模型. (2)同步非阻塞IO(Non-blocking  ...

  4. netty5 HTTP协议栈浅析与实践

      一.说在前面的话 前段时间,工作上需要做一个针对视频质量的统计分析系统,各端(PC端.移动端和 WEB端)将视频质量数据放在一个 HTTP 请求中上报到服务器,服务器对数据进行解析.分拣后从不同的 ...

  5. Jvm 内存浅析 及 GC个人学习总结

    从诞生至今,20多年过去,Java至今仍是使用最为广泛的语言.这仰赖于Java提供的各种技术和特性,让开发人员能优雅的编写高效的程序.今天我们就来说说Java的一项基本但非常重要的技术内存管理 了解C ...

  6. 从源码浅析MVC的MvcRouteHandler、MvcHandler和MvcHttpHandler

    熟悉WebForm开发的朋友一定都知道,Page类必须实现一个接口,就是IHttpHandler.HttpHandler是一个HTTP请求的真正处理中心,在HttpHandler容器中,ASP.NET ...

  7. 【深入浅出jQuery】源码浅析2--奇技淫巧

    最近一直在研读 jQuery 源码,初看源码一头雾水毫无头绪,真正静下心来细看写的真是精妙,让你感叹代码之美. 其结构明晰,高内聚.低耦合,兼具优秀的性能与便利的扩展性,在浏览器的兼容性(功能缺陷.渐 ...

  8. 浅析匿名函数、lambda表达式、闭包(closure)区别与作用

    浅析匿名函数.lambda表达式.闭包(closure)区别与作用 所有的主流编程语言都对函数式编程有支持,比如c++11.python和java中有lambda表达式.lua和JavaScript中 ...

  9. word-break|overflow-wrap|word-wrap——CSS英文断句浅析

    ---恢复内容开始--- word-break|overflow-wrap|word-wrap--CSS英文断句浅析 一 问题引入 今天在再次学习 overflow 属性的时候,查看效果时,看到如下结 ...

随机推荐

  1. ASP.NET没有魔法——第一个ASP.NET应用《MyBlog》

    创建一个ASP.NET MVC应用程序 在之前文章中介绍了ASP.NET中提供了3个开发动态网页的框架,分别是Web Form.MVC以及Web Pages,也大概介绍了它们的特点. 其中MVC对于其 ...

  2. Java高级工程师进阶路线

    第一部分:宏观方面 一. JAVA.要想成为JAVA(高级)工程师肯定要学习JAVA.一般的程序员或许只需知道一些JAVA的语法结构就可以应付了.但要成为JAVA(高级) 工程师,您要对JAVA做比较 ...

  3. IBM Minus One 简单字符处理

    IBM Minus One Time Limit: 2 Seconds      Memory Limit: 65536 KB You may have heard of the book '2001 ...

  4. 学习PID

    最近在想自己的文章有些是不是写的太难以理解了呢.........竟然好多人看了还是会直接问我很多问题....... 其实PID哈靠自己想像就能自己写出来自己的代码,也许是网上的讲的太过的高深什么积分微 ...

  5. iOS的异步绘制--YYAsyncLayer源码分析

    iOS的异步渲染 最近看了YYAsyncLayer在这里总结一下.YYAsyncLayer是整个YYKit异步渲染的基础.整个项目的Github地址在这里.你可以先下载了一睹为快,也可以跟着我一步一步 ...

  6. (转载)RESTful架构风格下的4大常见安全问题

    转载自<RESTful架构风格下的4大常见安全问题>,作者:马伟 伴随着RESTful架构风格的大量应用微服务架构的流行,一些本来难以察觉到的安全问题也逐渐开始显现出来.在我经历过的各种采 ...

  7. Java IO(IO流)-1

    IO流 第一部分 (outputStream/InputStream Writer/Redaer) IO流对象中输入和输出是相辅相成的,输出什么,就可以输入什么. IO的命名方式为前半部分能干什么,后 ...

  8. C陷阱和缺陷学习笔记

    这段时间把<C陷阱和缺陷>看了,没时间自己写总结.就转一下别人的学习笔记吧http://bbs.chinaunix.net/thread-749888-1-1.html Chapter 1 ...

  9. IDEA-最简单的struts2项目 关于lib项目的默认位置

    文件结构 struts.xml <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE struts ...

  10. OSW 快速安装部署

    关于在运行Oracle的环境下部署OSW具体好处不再多说,只需要知晓,在日常Oracle定位各类故障,osw的数据可以协助诊断问题.MOS很多文档也多处提到需要osw的监控数据. 一.前期资料准备 1 ...