zoukankan      html  css  js  c++  java
  • Espresso浅析和使用

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


    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

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

  • 相关阅读:
    autocomplete
    ORM组件 ELinq (一)首航之旅
    ORM组件 ELinq 系列
    Jet 驱动对CRUD的支持
    ORM组件 ELinq 更新日志
    年度开源力作ORM组件 ELinq诞生了
    Excel 连接字符串详解
    国内开源ORM组件 ELinq正式版发布
    Firebird 问题总结
    ORM组件 ELinq (二) 映射配置之Table
  • 原文地址:https://www.cnblogs.com/qcloud1001/p/7851858.html
Copyright © 2011-2022 走看看