Espresso 的核心是它可以与待测应用无缝同步测试操作的能力。默认情况下,Espresso 会等待当前消息队列中的 UI 事件执行(默认是 AsyncTask)完毕再进行下一个测试操作。这应该能解决大部分应用与测试同步的问题。

然而,应用中有一些执行后台操作的对象(比如与网络服务交互)通过非标准方式实现;例如:直接创建和管理线程,以及使用自定义服务。

此种情况,我们建议你首先提出可测试性的概念,然后询问使用非标准后台操作是否必要。某些情况下,可能是由于对 Android 理解太少造成的,并且应用也会受益于重构(例如,将自定义创建的线程改为 AsyncTask)。然而,某些时候重构并不现实。庆幸的是 Espresso 仍然可以同步测试操作与你的自定义资源。

这是基于idling的概念:Espresso等待app处于idle状态,才会执行下个动作和检查下个断言.

那么app处于idle状态是什么意思?Espresso检查下面几个场景:

  • 在当前消息队列中没有UI事件;
  • 在默认的AsyncTask线程池没有任务;

但是,如果app以其他方式执行长时间运行操作,Espresso不知道如何判断这些操作已经完成。如果是这样的话,可以通过编写自定义的IdelingResource来通知Espresso的等待时间。

idlingResource

它是一个简单的接口:
它代表了被测应用程序的资源,这个资源在测试执行时可以在后台异步工作。
接口定义了三个方法:

  • getName():必须返回代表idling resource的非空字符串;

  • isIdleNow():返回当前idlingresource的idle状态
    如果返回true,onTransitionToIdle()上注册的ResourceCallback必须必须在之前已经调用;

  • registerIdleTransitionCallback:通常此方法用于存储对回调的引用来通知idle状态的变化。

官方示例

需要入侵源代码,不做过多描述

  • Espresso IdlingResource 测试延时操作的使用

自定义 示例1

问题:
点击界面某个按钮后,新出现的页面会存在一个progressDialogFragment进行网络的请求数据,直到网络异常后者请求成功才会消失

其实这个时候如何不做任何处理的话,很明显,Espresso在点击按钮后的其他操作都会失败,它肯定会报错说NoViewsMatching

所以我们需要自定义一个IdlingResource:

public class ProgressFramentIdlingResource implements IdlingResource {private FragmentManager fragmentManager;private ResourceCallback resourceCallback;public ProgressFramentIdlingResource(FragmentManager fg) {fragmentManager = fg;}@Overridepublic String getName() {return ProgressFramentIdlingResource.class.getName();}@Overridepublic boolean isIdleNow() {//通过当前页面的fragment 是否存在以及可见,来判断。for (Fragment fragment:fragmentManager.getFragments()) {if(fragment != null && fragment.isVisible()) {resourceCallback.onTransitionToIdle();return false;}}return true;}@Overridepublic void registerIdleTransitionCallback(ResourceCallback callback) {resourceCallback = callback;}
}

上面的方法是没问题的,但是问题来了,如何才能够获取到framgentManager呢。正常情况下我们只是需要activity.getSupportFragmentManager就可以解决,但是我们在Espresso中获取到的activity的对象却是上一个界面的对象,所以我们还得去有方法能够获取到当前的Acitivity。还是伟大的google帮忙了

public Activity getActivityInstance(){try {testRule.runOnUiThread(new Runnable() {public void run() {Collection<Activity> resumedActivities = ActivityLifecycleMonitorRegistry.getInstance().getActivitiesInStage(Stage.RESUMED);for (Activity act: resumedActivities){Log.d("Your current activity: ", act.getClass().getName());currentActivity = act;break;}}});} catch (Throwable throwable) {throwable.printStackTrace();}return currentActivity;}

上面的方法就解决了获取当前Activity的问题了,具体的使用

IdlingResource idlingResource = new ProgressFramentIdlingResource(((UpdateSubjectActivity)getActivityInstance()).getSupportFragmentManager());
Espresso.registerIdlingResources(idlingResource);
****
Espresso.unregisterIdlingResources(idlingResource);

自定义 示例2

假设你使用IntentService来做一些长时间运算,然后通过broadcast将结果返回给activity。我们希望Espresso一直等到结果返回,才来验证界面显示正确。

为了实现IdlingResource,需要重写3个函数:getName(),registerIdleTransitionCallback(),isIdleNow()

@Override
public String getName() {return IntentServiceIdlingResource.class.getName();
}@Override
public void registerIdleTransitionCallback(ResourceCallback resourceCallback) {this.resourceCallback = resourceCallback;
}@Override
public boolean isIdleNow() {boolean idle = !isIntentServiceRunning();if (idle && resourceCallback != null) {resourceCallback.onTransitionToIdle();}return idle;
}private boolean isIntentServiceRunning() {ActivityManager manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);for (ActivityManager.RunningServiceInfo info : manager.getRunningServices(Integer.MAX_VALUE)) {if (RepeatService.class.getName().equals(info.service.getClassName())) {return true;}}return false;
}

idle逻辑是在isIdleNow()实现的。在这个例子中,我们通过查询ActivityManager来检查IntentService是否正在运行。如果IntentService停止运行,我们调用resourceCallback.onTransitionToIdle()来通知Espresso

为了让Espresso等待自定义的idling resource,你需要注册它。在测试代码的@Before方法中执行注册,在@After中执行注销

@Before
public void registerIntentServiceIdlingResource() {Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();idlingResource = new IntentServiceIdlingResource(instrumentation.getTargetContext());Espresso.registerIdlingResources(idlingResource);
}@After
public void unregisterIntentServiceIdlingResource() {Espresso.unregisterIdlingResources(idlingResource);
}

自定义 示例3

public class MainActivityIdlingResource implements IdlingResource {private ResourceCallback mCallback;private final long startTime;private final long waitingTime;ActivityTestRule testRule;public MainActivityIdlingResource(long waitingTime, ActivityTestRule testRule){this.startTime = System.currentTimeMillis();this.waitingTime = waitingTime;this.testRule =  testRule;}@Overridepublic String getName() {return MainActivityIdlingResource.class.getSimpleName();}@Overridepublic boolean isIdleNow() {//当Activity 出现时if(ActivityUtils.getActivityInstance(testRule).getClass().getSimpleName().equals("MoaFragmentTabActivity")){mCallback.onTransitionToIdle();System.out.println("打印");return true;}return false;}@Overridepublic void registerIdleTransitionCallback(ResourceCallback callback) {this.mCallback=callback;}
}
IdlingResource idlingResource1=new MainActivityIdlingResource(1000,  mActivityTestRule);Espresso.registerIdlingResources(idlingResource1);//等待主界面后执行后面的代码...Espresso.unregisterIdlingResources(idlingResource1); //等代码调试完记得关闭

自定义 示例4

public class ListAdapterIdlingResource implements IdlingResource {private IdlingResource.ResourceCallback mCallback;private final long startTime;private final long waitingTime;private ListView listView;public  ListAdapterIdlingResource(long waitingTime,ListView listView){this.startTime = System.currentTimeMillis();this.waitingTime = waitingTime;this.listView=listView;}@Overridepublic String getName() {return ListAdapterIdlingResource.class.getSimpleName();}@Overridepublic boolean isIdleNow() {//当网络数据加载完,才设置适配器,故可以通过适配器是否为空值来判断其异步数据加载是否完成if(listView.getAdapter().getCount() != 0){mCallback.onTransitionToIdle();System.out.println("打印");return true;}return false;//通过时间来限制其异步加载/*long elapsed = System.currentTimeMillis() - startTime;boolean idle = (elapsed >= waitingTime);if (idle) {System.out.println("打印");mCallback.onTransitionToIdle();}return idle;*/}@Overridepublic void registerIdleTransitionCallback(ResourceCallback callback) {this.mCallback=callback;}
}
        IdlingResource idlingResource = new ListAdapterIdlingResource(1000, (((PullListView) ActivityUtils.getActivityInstance(mActivityTestRule).findViewById(R.id.pull)).getRefreshableView()));//等待后台ListView加载完数据后执行后面的代码...//释放对其异步空闲处理类Espresso.unregisterIdlingResources(idlingResource);

(4.5.5.6)Espresso的进阶: IdlingResource相关推荐

  1. Espresso自动化测试(十一) - IdlingResource

    Espresso测试有个很强大的地方是它在多个测试操作中是线程安全的.Espresso会等待当前进程的消息队列中的UI事件,并且在任何一个测试操作中会等待其中的AsyncTask结束才会执行下一个测试 ...

  2. 显示空闲链表和隐式空闲链表_使用空闲资源添加Espresso UI测试

    显示空闲链表和隐式空闲链表 You may want to read the Spanish version of this article in Droid-Latam's publication ...

  3. android espresso跨程序,在Espresso Android中正确使用IdlingResource的方法

    我正在用Espresso编写UI测试.应用程序与服务器紧密配合,因此在许多情况下,我需要等待任意一个值进行计算,或者获取和显示数据.Espresso建议使用IdlingResource. 我的Idli ...

  4. java espresso车架_Espresso UI自动化测试框架

    前言 Espresso是谷歌大力推荐的一套测试框架,从Android studio2.2版本开始,google就开始支持在as上espresso自动生成单元测试代码. Espresso测试运行速度很快 ...

  5. Espresso Idling Resource

    前沿 上一篇进行Espresso 安装方面介绍,也就是测试环境的设置.下面几篇会对照官方文档进行一个分析.避免与主题脱节.关于Espresso文章不分先后. 1.翻译官网文档 Espresso的核心是 ...

  6. 使用espressos idlingresource获得最高的Android测试速度

    When you first start learning UI testing with Espresso, it begins fairly quickly and easily by codin ...

  7. Espresso IdlingResource 测试延时操作的使用

    在Espresso 自动化测试的使用中已经把一些基本的测试使用方法告诉大家了,单是数据加载之类的延时操作却没有详细说明,这篇文介绍下Espresso 延时操作的使用 之前有在谷歌搜索相关资料,确实有不 ...

  8. 【Android进阶】20、音频播放:SoundPool 类、单元测试:Espresso框架

    文章目录 20.1 创建 SoundPool 20.2 访问 assets 20.3 加载音频文件 20.4 播放音频 20.5 单元测试 20.6 创建测试类 20.7 配置测试类 20.8 编写测 ...

  9. android测试篇(三)单元测试之UI测试 Espresso学习与实践

    前言 上一章并没有说仪器化测试,仪器化测试存放在src/androidTest目录中,仪器化测试即UI测试. 本文并没有多加理解,按照Android UI 测试指南之 Espresso抄袭(会标注转载 ...

最新文章

  1. Win7/Win8 系统下安装Oracle 10g 提示“程序异常终止,发生未知错误”的解决方法...
  2. rhel6编译ssh的src.rpm包并修改spec参数
  3. javaScript基本功001
  4. shell脚本[] [[]] -n -z 的含义解析
  5. Matlab的内部常数
  6. cmenu 隐藏子项中的一个子项_QML中的模型-视图-代理
  7. 12位18Bb20计算公式c语言,C语言的一些简单题目,没有答案,哪位大神帮忙做一下!!!...
  8. SAP ABAP实用技巧介绍系列之could not create BAdI implementation
  9. 你买过假芯片吗?元器件专家为您揭秘假冒芯片的套路!
  10. Mysql-索引的基础和类型
  11. 图灵社区 : 阅读 : 谁说Vim不是IDE?(三)
  12. LeetCode 256. 粉刷房子(DP)
  13. 计算机系统账户被锁定,帐号已经被系统锁定是什么意思
  14. 手把手教你制作AppPreview视频并上传到appStore进行审核
  15. 三星刷完机后一直停留在Samsung页面
  16. windows各类密码搜集
  17. TiddlyWiki笔记入门之多维度标签--发散思维与收敛思维的乐园。
  18. matlab程序 直线插补,无聊写matlab仿真直线插补算法
  19. java secretkey用法_Java SecretKeyFactory.generateSecret方法代码示例
  20. Flowable入门系列文章11 - Flowable API 01

热门文章

  1. 狄利克雷卷积_狄利克雷卷积学习笔记
  2. Vue实现动态路由导航
  3. emwin添加图标和图片
  4. 互联网络业的十大发展趋势
  5. Ubuntu 9.10 如何安装rais环境
  6. 百事可乐AI人工智能生产过程破光
  7. 软件测试类型——集成测试
  8. Design contains shelved or modified (but not repoured) polygons. The result of DRC is not correct.
  9. Python自动抢红包,从此再也不会错过微信红包了!
  10. 计算机怎黑夜模式么启动,Win10系统电脑夜间模式怎么开启/关闭的方法