在上一篇博客笔者介绍了Espresso的基础用法,在文章最后抛出了一个问题,简短的说就是异步的情况下,如何保证测试的正确进行。

如果没有看过的,建议先看这一篇,传送门在这里:

搬砖之余来一杯意式浓缩咖啡(Espresso基础用法)

那么开始这篇博客的正题了

  • 明确问题
  • 解决方案
  • 优雅的实现方式
  • 实例演示

明确问题

在很多时候,我们都会进行网络请求,当进行网络请求的时候,由于网络的原因,我们不确定它什么时候可以返回给我结果。如果还是直接用上节的测试方法,很大概率会出现问题,因为测试代码是无脑顺序执行的,不知道什么时候它该停下来等待网络请求。

你或许会想到一个骚操作:在测试的时候,我在请求网络的时候让它睡个几秒(几秒你还不请求完成?),然后在继续执行测试代码。哈哈,这波操作还是很骚的,但是会遇到一个问题:你还是不确定这个等待时间是多少;如果睡时间短了,还是会测试错误,如果睡时间长了,就会浪费等待时间。所以,这个骚操作还是不可取的…有风险啊

那么该怎么办???选择狗带?

解决方案

既然Espresso是Google爸爸推崇的UI自动化测试工具,这个问题肯定有解决方法的。从上面的问题我们可以知道问题的根本原因就是我们不知道它什么时候完成网络请求。准确的说是异步操作的完成。

在这个基础上,Google给我们提供了IdlingResource这样一个接口
通过这个接口,在我们测试的Activity中实现这个接口,通过里面的回调方法在通知测试类,我的异步操作完成了,你可以继续你的下一步测试了。

 public interface IdlingResource {/*** 用来标识 IdlingResource 名称*/public String getName();/*** 当前 IdlingResource 是否空闲 .*/public boolean isIdleNow();/**注册一个空闲状态变换的ResourceCallback回调*/public void registerIdleTransitionCallback(ResourceCallback callback);/*** 通知Espresso当前IdlingResource状态变换为空闲的回调接口*/public interface ResourceCallback {/*** 当前状态转变为空闲时,调用该方法告诉Espresso*/public void onTransitionToIdle();}}

哇,看似好牛逼啊,但是这样的话我需要测试的每个Activity都要实现这个接口,还要实现这么多方法,多繁琐啊。会出现好多冗余的代码。在Activity添加代码是肯定要的了,但是我们可以减少冗余的代码量。以一个优雅的方式去实现。

优雅的实现方式

在使用IdlingResource之前,我们要添加两个库

implementation 'com.android.support.test.espresso:espresso-idling-resource:3.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-contrib:3.0.2'

注意第一个库要用implementation而不是androidTestImplementation,因为我们要在测试代码的外面使用IdlingResource,使用androidTestImplementation会找不到这个类,编译就不能通过。

接下来我们创建一个类实现IdlingResource接口

public class SimpleCountingIdlingResource implements IdlingResource {private final String mResourceName;//这个counter值就像一个标记,默认为0private final AtomicInteger counter = new AtomicInteger(0);private volatile ResourceCallback resourceCallback;public SimpleCountingIdlingResource(String resourceNme){mResourceName=resourceNme;}@Overridepublic String getName() {return mResourceName;}@Overridepublic boolean isIdleNow() {return counter.get()==0;}@Overridepublic void registerIdleTransitionCallback(ResourceCallback callback) {resourceCallback=callback;}//每当我们开始异步请求,把counter值+1public void increment(){counter.getAndIncrement();}//当我们获取到网络数据后,counter值-1public void decrement(){int counterVal=counter.decrementAndGet();//如果counterVal的值为0说明异步结束,执行回调if(counterVal==0){if(resourceCallback!=null){resourceCallback.onTransitionToIdle();}}if(counterVal<0)//如果小于0,抛出异常throw new IllegalArgumentException("Counter has been corrupted!");}
}

这个类定义了一个标记counter,通过这个标记的值,来判断何时接口回调,从而测试类可以知道这个时候它的异步任务完成了,这时候就可以继续进行下一步的测试。

但是SimpleCountingIdlingResource这个类看起来还是有点杂乱的,我们再用一个管理类来封装它,用它处理业务部分。

ublic class EspressoIdlingResource {private static final String RESOURCE = "GLOBAL";private static SimpleCountingIdlingResource mCountingIdlingResource =new SimpleCountingIdlingResource(RESOURCE);public static void increment(){mCountingIdlingResource.increment();}public static void decrement(){mCountingIdlingResource.decrement();}public static IdlingResource getIdlingResource(){return  mCountingIdlingResource;}
}

所以最终我们只需要直接使用EspressoIdlingResource这个类就行了。

说这么多还是太抽象了,下面用一个实例来感受一下。

实例演示

还是用之前的登录来进行测试,不过添加了一个线程睡眠来模拟一个网络请求的等待时间。

MainActivity.class

public class MainActivity extends AppCompatActivity {EditText edName;EditText edPass;Button btClick;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);btClick=(Button)findViewById(R.id.bt_click);edName=(EditText) findViewById(R.id.ed_username);edPass=(EditText) findViewById(R.id.ed_pass);btClick.setText("登录");}public void clickButton(View view){btClick.setText("登录中...");MyThread myThread=new MyThread();myThread.start();}class MyThread extends Thread{@Overridepublic void run() {super.run();try {Thread.sleep(5000);  //让该线程睡眠5秒} catch (InterruptedException e) {e.printStackTrace();}if(edName.getText().toString().equals("jasonking")&&edPass.getText().toString().equals("123")){runOnUiThread(new Runnable() {@Overridepublic void run() {btClick.setText("登录成功");}});}else{runOnUiThread(new Runnable() {@Overridepublic void run() {btClick.setText("登录失败");}});}}}}

如果我们继续用之前的测试用例,运行测试会发现,测试不能通过。因为我们期盼的是“登录成功”,但是5s内,我们得到的结果是“登录中…”,只有5秒之后才可能返回"登录成功。

接下来,我们就可以使用之前准备的工具类了,对这个Activity进行标记

异步开始前的标记

  public void clickButton(View view){btClick.setText("登录中...");//在开始异步请求前添加这行代码,意味着开始了异步EspressoIdlingResource.increment();MyThread myThread=new MyThread();myThread.start();}

异步结束后的标记

class MyThread extends Thread{@Overridepublic void run() {//省略...//异步结束的时候,添加这行代码if (!EspressoIdlingResource.getIdlingResource().isIdleNow()) {EspressoIdlingResource.decrement();}}}

添加这个方法,获取这个类的标识

    @VisibleForTestingpublic IdlingResource getCountingIdlingResource() {return EspressoIdlingResource.getIdlingResource();}

最后再修改一下测试类

MyEspressoAsyncTest.class

相比较之前的,这里多做了3个步骤

  • 获取需要测试的Activity的标识,之后为了添加到异步监听集合中
  • 注册异步监听
  • 在测试结束后取消注册,释放资源
@RunWith(AndroidJUnit4.class)
@LargeTest
public class MyEspressoAsyncTest {@Rulepublic ActivityTestRule<MainActivity> mActivityRule = new ActivityTestRule<>(MainActivity.class);private IdlingResource idlingResource;@Beforepublic void setUp() throws Exception{//获取这个类的标识idlingResource=mActivityRule.getActivity().getCountingIdlingResource();}@Testpublic void onLoadingFinished(){//清空文本框,然后输入用户名jasonking,关闭软键盘onView(withId(R.id.ed_username)).perform(clearText(),replaceText("jasonking"),closeSoftKeyboard()).check(matches(withText("jasonking")));//清空文本框,然后输入密码,关闭软键盘onView(withId(R.id.ed_pass)).perform(clearText(),replaceText("123"),closeSoftKeyboard()).check(matches(withText("123")));//点击按钮检查文本是不是登录onView(withId(R.id.bt_click)).check(matches(withText("登录"))).perform(click());//注册异步监听,,此时测试会挂起,等待网络请求结束后,继续测试IdlingRegistry.getInstance().register(idlingResource);Log.d(TAG, "setUp: "+"请求网络请求完成");//继续执行代码onView(withId(R.id.bt_click)).check(matches(withText("登录成功")));}@Afterpublic void release() throws Exception {// 当然,我们需要在测试结束后取消注册,释放资源IdlingRegistry.getInstance().unregister(idlingResource);}
}

运行测试可以看到结果是pass的

搬砖之余来一杯意式浓缩咖啡(Espresso高级用法)相关推荐

  1. 搬砖之余来一杯意式浓缩咖啡(Espresso基础用法)

    就知道,这肯定是杯假咖啡,搬砖还有时间喝咖啡!!! 年轻人,别急躁吗,看完之后,你会发现可能真的可以空出一大把时间去喝咖啡了. 我信了你的邪了. -,不信?你就往下看呗 何为意式浓缩咖啡(Espres ...

  2. 软件系统中的颗粒度_意式浓缩咖啡丨甘醇香浓余韵长,研磨的度与质千万别忽视...

    8秒的时间,一杯35ml的意式浓缩咖啡就做成了!这事竟然出现在一家即将要开业的咖啡馆.看着这位经朋友介绍的陌生老板.吧台里价格不菲的La Marzocco咖啡机.以及Mythos One磨豆机研磨出& ...

  3. 解构里面再次解构_解构后的咖啡:焙炒,研磨和分层,以获得更浓的意式浓缩咖啡

    解构里面再次解构 Over a year ago, I developed a technique called staccato espresso where I used a sifter to ...

  4. 随心所欲的醇香,Barsetto百胜图TripressoES意式便携咖啡机测评

    让视野填充斑斓色彩,让心情在田园风光中陶醉,生活从此变得更加富有色彩,这也许是很多人会来一场说走就走的旅行的原因吧.我也是个纯粹的旅行爱好者,而在旅行中我一定会带上我心爱的宝贝--Barsetto百胜 ...

  5. 第十三届蓝桥杯国赛 C++ B 组 J 题——搬砖(AC)

    目录 1.搬砖 1.题目描述 2.输入格式 3.输出格式 4.样例输入 5.样例输出 6.数据范围 7.原题链接 2.解题思路 3.Ac_code 1.搬砖 1.题目描述 这天,小明在搬砖. 他一共有 ...

  6. dnf最新地图编号2020_2020手游崛起端游没落?网易新端游好玩刺激能搬砖,网友:妙...

    2020真的是手游界丰收的一年,先是有以休闲养生吸引到无数用户喜欢爆火的<江南百景图>和<阴阳师:妖怪屋>,又有硬核武侠手游<天涯明月刀>以及即将要终测的东方幻想题 ...

  7. Java:JVM+数据库(搬砖整理,侵权删文)

    Java:JVM+数据库(搬砖整理,侵权删文) 十一.JVM 1.Java内存区域 1.说一下 JVM 的主要组成部分及其作用? ​ JVM包含两个子系统和两个组件,两个子系统为Class loade ...

  8. 搬砖中招勒索病毒,自我拯救电脑系统经历

    创作立场声明:本文所有物品均为自费购入,所码字为个人分享,观点拙笨在所难免,欢迎拍砖. [写作说明]:对网络安全了解有限,搬砖过程中被勒索病毒命中,放弃谈判,记录下清理电脑重新开始的历程 1.问题出现 ...

  9. 提升搬砖效率的神兵利器

    前两天有个小伙伴在后台留言,除了核心知识的巩固之外,还有没有提升编码效率的办法. 这小伙伴,可算是问对人了,今天我正好在 GitHub 上发现了一个提升搬砖效率的利器. 用上它之后,不能保证你能升职加 ...

最新文章

  1. 宠粉福利,100G网盘最新架构技术资料合集限时领
  2. MultiByteToWideChar和WideCharToMultiByte
  3. 压测导致mysql数据库CPU很高_排查压测问题引发的系统性能调优过程
  4. html5能实现网络游戏吗,kbengine + cocos2d_js实现html5网络游戏mmorpg(全套代码+资源)...
  5. MATLAB如何用循环分割,利用Matlab进行分割提取浮游生物
  6. TIM怎么设置禁止窗口抖动 TIM防抖设置技巧
  7. oracle企业版配置,在 Oracle 数据库 11
  8. ubuntu17安装mysql后数据库乱码_linux安装MySQL数据库,设置编码为utf8
  9. Java环境安装手册
  10. ubuntu16.0.4安装mysql5.7以及设置远程访问
  11. Linux 下 Git 的源码安装
  12. Gut Microbes:南医大刘星吟组-孤独症的基因变异与肠道微生物群、代谢物和细胞因子的改变有关...
  13. 视觉SLAM十四讲第一讲
  14. 图文展示目标检测的现代发展历史
  15. CDH--彻底解决问题----时钟异常
  16. jquery 录屏_Fundebug录屏插件更新至0.6.0
  17. Tommy Hilfiger 宣布,F1世界冠军Lewis Hamilton担任TOMMY HILFIGER全球男装代言人
  18. kodi+java版_[转] Emby+KODI--完美的NAS多媒体方案
  19. rk3399 中间层移除短按power息屏待机+永不深度睡眠
  20. PPT封面设计的一些心得

热门文章

  1. 通过操作swap文件来扩大或缩小swap空间
  2. 搭建802.1X服务器及如何使用路由器接入和桥接(WDS)
  3. Zotero同步OneDrive
  4. TCP的CLOSING状态发生条件
  5. getchar()的使用方法——给scanf当爹又当妈
  6. 20 数据存储服务器集群的伸缩性设计
  7. 风控策略精准运维的制胜点,一个重要却容易被轻视的内容
  8. ssoj4021: 西行妖下(yuyuko)
  9. 实战|TF Lite 让树莓派记下你的美丽笑颜
  10. java读取最新网易云音乐API