Android Espresso Test UI

ps:Espresso英文文档,本人翻译水平有限,可能存在不足

Espresso是Google官方提供的Android UI自动化测试的框架。

使用Espresso能写出简洁,美观,可靠的android ui test(好处)

Espresso的重要组成部分:

 1.Espresso:通过onView()和onData()与view交互的进入点,它的api不依赖任何view

 2.ViewMatchers:  实现了Matcher<? super View>的集合对象。通过onView()来定位当前的view 

 3.ViewActions:   具备操作方法(例如点击操作)的集合对象,它里面的操作可以通过   
                  ViewInteraction.perform()来实现 

 4.ViewAssertions   用它可以断言,查看当前view的状态 ,ViewInteraction.check() 会执行它 

来张Espresso的小抄:

这里写图片描述

案例:

onView(withId(R.id.main_view)).perform(click()).check(matches(isDisplayed())); 

 分析:withId()通过id获取到ViewMatcher, 
      click()是一个viewAction(即操作), 
      matches()是一个ViewAssertions  

Espresso的使用步骤:

步骤(一):加载view

1.普通的view用onView()加载视图:

1.1:R.id.xx是唯一的:   onView(withId(R.id.main_view))

1.2:存在view的id是不唯一:若是通过以上方法会报错,com.google.android.apps.common.testing.ui.espresso.AmbiguousViewMatcherException

    解决方式:缩小范围,通过查看所要找到的view属性,采用多个属性来查找

    案例:若是两个edittext中的id相同,text内容不同,现在要获取text内容为"Hello!":

         //通过id,text属性来确定所要查找的edittextview:
          onView(allOf(withId(R.id.my_view), withText("Hello!"))) 

2.AdapterView类型(例如gridview,listview,spinner)中的itemView:要通过onData()加载视图

特殊情况: 为了解决view中R.id问题(可能不存在,不唯一)的问题,获取view视图可以通过自定义(或者已经存在)的ViewMatchers  

步骤(二):执行action

在view中执行一个操作:
在匹配好指定view(即onView()或者onData())后,可以通过perform()来执行ViewAction

 案例之view的点击:        onView(withId(R.id.main_view)).perform(click())

 案例之view执行多个操作:  onView(...).perform(typeText("Hello"), click());

 案例之ScrollView中的view执行:onView(...).perform(scrollTo(), click());
      理解:执行click()随着sroolrto() ,确保执行操作在其他操作之前  

步骤(三):检查view是否包含某种assertion

当前的view可以通过check()执行Assertions 。
通常通过matches()使用 assertion,matches()是通过 ViewMatcher来断言当前view的状态 

案例1:检查view是否包含“Hello”内容

         onView(...).check(matches(withText("Hello!")));

案例2:若是view没有明确displayed的情况下,不能将assertions放到onView()中,要将检查放到检查代码块中:

   // view的disPlay是未知情况下,assertions(断言)view的内容是否是“Hello!”,以下代码是不好的 

   onView(allOf(withId(...), withText("Hello!"))).check(matches(isDisplayed()));

   若是已经明确view已经显示,这代码是好的。

注意点:在view不显示或者view不在当前视图中这两种情况下,使用assertions情况

使用IDE开始编写:

(一)eclipse中Espresso的使用:

配置Espresso, 通过添加以下静态jar:

这里写图片描述

github上包含Android Studio和eclipse的对应项目 
(下载全部案例后,使用eclipse的,选择BasicSampleBundled):

eclipse的案例:
https://github.com/googlesamples/android-testing/tree/master/ui/espresso/BasicSampleBundled

(二)Android Studio中Espresso的使用:

第一步:添加 Android Support Repository,(已经添加的,这步省略)

这里写图片描述

第二步:在Gridle中dependencies{}添加各自需求的jar:

 //Android JUnit Runner
  androidTestCompile 'com.android.support.test:runner:0.5'

 // JUnit4 Rules
 androidTestCompile 'com.android.support.test:rules:0.5'

 // Espresso core
  androidTestCompile 'com.android.support.test.espresso:espresso-core:2.2.2'

   //测试DatePicker, RecyclerView, Drawer actions,  
        Accessibility checks, CountingIdlingResource所需

   androidTestCompile 'com.android.support.test.espresso:espresso-contrib:2.2.2'

   //测试WebView所需
     androidTestCompile 'com.android.support.test.espresso:espresso-web:2.2.2'

     //测速异步线程所需
     androidTestCompile 'com.android.support.test.espresso:espresso-idling-resource:2.2.2'

最后别忘记,sync Now

第三步:创建测试包的路径,切换到project视图下,找到对应的项目,在src下创建一个文件,命名为androidTest/java,然后在anroidTest/java路径下创建一个包,填入项目的包名(已经存在对应项目的android test包,省略这步)

这里写图片描述

第四步:在xxx.xxx.xx(androidStudio)下创建对应的测试类,按照Espresso使用方式,编写测试代码

这里写图片描述

第五步:创建test configuration: Edit Configurations–> +–>Android Tests configuration–>选择module和添加AndroidJUnitRunner ,name 自己定义,module 选择要测试的项目
这里写图片描述

最后一步:运行测试项目

这里写图片描述

测试案例:Button点击和ListView的item点击测试:

在配置Espresso的jar你会发现一些问题:

Error:Conflict with dependency 'com.android.support:support-annotations'. Resolved versions for app (23.3.0) and test app (23.1.1) differ.
See http://g.co/androidstudio/app-test-app-conflict for details. 
这是两个注解包冲突了

解决方式:采用你当前项目中com.android.support:support-annotations(个人这边是23.3.0版)

gradle中jar依赖:

dependencies {

  testCompile 'junit:junit:4.12'

  compile 'com.android.support:appcompat-v7:23.3.0'
  //添加注解,包含test
  compile 'com.android.support:support-annotations:23.3.0'

  //解决冲突
   androidTestCompile  'com.android.support:support-annotations:23.3.0' 

  // Android JUnit Runner
   androidTestCompile 'com.android.support.test:runner:0.5' 

   // JUnit4 Rules
   androidTestCompile 'com.android.support.test:rules:0.5'

    // Espresso core
    androidTestCompile 'com.android.support.test.espresso:espresso-core:2.2.2' 

   }

Button所在的xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:orientation="vertical"
    tools:context="com.szejq.testdemo.MainActivity">

    <TextView
        android:id="@+id/main_change"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"

        android:text="Hello World!" />
    <EditText
        android:id="@+id/main_edit"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
    <Button
        android:id="@+id/main_btn"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:onClick="changContent"
        android:text="button"/>
    <ListView
        android:id="@+id/main_list"
        android:layout_width="match_parent"
        android:layout_height="match_parent"></ListView>
</LinearLayout>

myadapter_item(listView中item)的xml:

<TextView xmlns:android="http://schemas.android.com/apk/res/android"
           android:layout_width="match_parent"
           android:id="@+id/myadapter_item"
           android:layout_height="match_parent">

</TextView>

MainActivity.java的代码:

public class MainActivity extends AppCompatActivity {
   private ListView listView;;
    private List<String>  list;
    private  TextView showChangge_tv;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
    }

    private void initView() {
         listView=(ListView) this.findViewById(R.id.main_list);
        list=new ArrayList<>();
        for (int i=1;i<6;++i){
            list.add(String.valueOf(i));
        }
         listView.setAdapter(new MyAdapter());
        showChangge_tv= (TextView)     this.findViewById(R.id.main_change);
    }

    public void changContent(View v){
        showToas("onClick");
    }
    public Toast  toast;
    public void showToas(String content){
        if(toast!=null){
            toast.cancel();
        }
        toast=Toast.makeText(getApplicationContext(),content,Toast.LENGTH_SHORT);
        toast.show();
    }
    private  class MyAdapter extends BaseAdapter implements View.OnClickListener{
        @Override
        public int getCount() {
            return list.size();
        }
        @Override
        public Object getItem(int position) {
            return list.get(position);
        }
        @Override
        public long getItemId(int position) {
            return position;
        }
        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            ViewHolder  viewHolder;
            if(convertView==null){
                viewHolder=new ViewHolder();
                convertView=View.inflate(MainActivity.this,R.layout.myadaper_item,null);
                viewHolder.textview=(TextView) convertView.findViewById(R.id.myadapter_item);
                convertView.setTag(viewHolder);
            }else{
                viewHolder=(ViewHolder) convertView.getTag();
            }
            viewHolder.textview.setText(list.get(position));
            viewHolder.textview.setOnClickListener(this);
            return convertView;
        }

        @Override
        public void onClick(View v) {
           showChangge_tv.setText(((TextView)v).getText());
        }
    }
    static   class  ViewHolder{
        TextView  textview;
    }

}

MainActivity对应测试类中代码(重要点):

注意点:@xx这些注解不能少,导入jar需通过static import

package com.szejq.testdemo;

import android.support.test.espresso.Espresso;
import android.support.test.espresso.ViewAction;
import android.support.test.espresso.ViewInteraction;
import android.support.test.espresso.action.ViewActions;
import android.support.test.espresso.matcher.ViewMatchers;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.LargeTest;
import android.view.View;

import org.hamcrest.Matcher;
import org.hamcrest.Matchers;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;

import static android.support.test.espresso.Espresso.onData;
import static android.support.test.espresso.Espresso.onView;
import static android.support.test.espresso.action.ViewActions.click;
import static android.support.test.espresso.assertion.ViewAssertions.matches;
import static android.support.test.espresso.matcher.ViewMatchers.withId;
import static android.support.test.espresso.matcher.ViewMatchers.withText;

/**
 * Created by Administrator on 2016/7/19.
 */

@RunWith(AndroidJUnit4.class) 

@LargeTest 

public class MainActivityTest {

    @Rule   // @Rule指定被测试的类
    public ActivityTestRule<MainActivity>  activityActivityTestRule 
                =new ActivityTestRule<MainActivity>(MainActivity.class); 

    @Test //@Test指定需测试的功能,方法名随意定
    public void changContentTest(){
           Matcher<View>  matcher= ViewMatchers.withId(R.id.main_change); 

           //获取R.id.main_change为id的view
           ViewInteraction  viewInteraction= Espresso.onView(matcher); 

           ViewAction  viewAction= ViewActions.click();

           viewInteraction.perform(viewAction);//点击事件

          // 简写方式:onView(withId(R.id.main_change)).perform(click());
    }

    @Test
    public void testAdapterView(){

        //listView中内容为“2”的item点击( listviwe中数据类型String,所对应的值为“2” )
       onData(Matchers.allOf(             
                Matchers.is(Matchers.instanceOf(String.class)),Matchers.is("2")  
               ) ).perform(click());

       //检查上一步点击事件,有没有执行成功
         onView(withId(R.id.main_change)).check(matches(withText("2")));

    }

}

运行结果:

这里写图片描述

下一篇: Android Espresso测试Intents,WebView

stackOverFlow上关于Espresso:
http://stackoverflow.com/questions/tagged/android-testing

测试项目代码:
http://download.csdn.net/detail/hexingen/9581516

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值