(4.5.5.6)Espresso的进阶: IdlingResource
来源:互联网 发布:淘宝八大山人书法全集 编辑:程序博客网 时间:2024/06/09 14:05
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; } @Override public String getName() { return ProgressFramentIdlingResource.class.getName(); } @Override public boolean isIdleNow() { //通过当前页面的fragment 是否存在以及可见,来判断。 for (Fragment fragment:fragmentManager.getFragments()) { if(fragment != null && fragment.isVisible()) { resourceCallback.onTransitionToIdle(); return false; } } return true; } @Override public 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()
@Overridepublic String getName() { return IntentServiceIdlingResource.class.getName();}@Overridepublic void registerIdleTransitionCallback(ResourceCallback resourceCallback) { this.resourceCallback = resourceCallback;}@Overridepublic 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中执行注销
@Beforepublic void registerIntentServiceIdlingResource() { Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation(); idlingResource = new IntentServiceIdlingResource(instrumentation.getTargetContext()); Espresso.registerIdlingResources(idlingResource);}@Afterpublic 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; } @Override public String getName() { return MainActivityIdlingResource.class.getSimpleName(); } @Override public boolean isIdleNow() { //当Activity 出现时 if(ActivityUtils.getActivityInstance(testRule).getClass().getSimpleName().equals("MoaFragmentTabActivity")) { mCallback.onTransitionToIdle(); System.out.println("打印"); return true; } return false; } @Override public 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; } @Override public String getName() { return ListAdapterIdlingResource.class.getSimpleName(); } @Override public 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;*/ } @Override public 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
- Espresso IdlingResource 测试延时操作的使用
- (4.5.5.3)Espresso的进阶: ViewAction
- (4.5.5.5)Espresso的进阶: ViewAssertions
- (4.5.5.4)Espresso的进阶: AdapterViewProtocol
- Espresso自动化测试(十一) - IdlingResource
- (4.5.5.4)Espresso的进阶: OnView & onData & Matchers
- (4.5.5.9)Espresso之UiAutomator2与Espresso的结合
- (4.5.5.10)Espresso之Robotium与Espresso的结合
- (4.5.5.2)Espresso的基础
- Espresso自动化测试(十三)- UiAutomator2与Espresso的结合
- (4.5.5.1) Espresso的简介、下载和安装
- 大牛们的浓咖啡(Espresso)简单介绍
- (4.5.5.7)Espresso之Intent测试
- Espresso指南二(Espresso意图)
- Espresso
- Espresso 自动化测试(四)-中文字符的输入
- Espresso 自动化测试(五)- onData() 的使用
- (4.5.5.5)Espresso的进阶: ViewAssertions
- 开张
- ThinkPHP分页总结
- 【最小生成树】POJ 2349 Arctic Network
- 如何绕过PowerShell Execution Policy限制?
- (4.5.5.6)Espresso的进阶: IdlingResource
- bzoj2152: 聪聪可可
- python运行异常
- 基于 React Native 的开源项目
- HBase数据导入之completebulkload方式
- 第三十九讲项目七
- 微服务开发的12项要素
- Android AndroidManifest.xml文件的android:supportsRtl属性详解
- Deep learning Reading List