Android自动化测试入门(三)Espresso

栏目: IT技术 · 发布时间: 4年前

内容简介:Android自动化测试入门(三)EspressoEspresso是谷歌力推的一个UI自动化测试框架,新建一个Andrdoid工程的时候之前使用UI Automator的时候,我们经常在不同的指令之间添加一个时间延时保证手机端执行完成,在Espresso直接使用onView(),onView()会等待界面执行完在执行下一步。

Android自动化测试入门(三)Espresso

Espresso是谷歌力推的一个UI自动化测试框架,新建一个Andrdoid工程的时候 默认就引入了Espresso的核心依赖 ,所以作为Android开发者,非常有必要学习这个框架。

之前使用UI Automator的时候,我们经常在不同的指令之间添加一个时间延时保证手机端执行完成,在Espresso直接使用onView(),onView()会等待界面执行完在执行下一步。

Espresso和UI Automator一样,也是在项目的app/src/androidTest文件夹下编写测试代码

下面先来个开胃菜

测试TextView是否已经显示

新建一个测试类HelloWorldTest

@RunWith(AndroidJUnit4.class)
public class HelloWorldTest {

    @Rule
    public ActivityTestRule<MainActivity> activityRule =
            new ActivityTestRule<>(MainActivity.class);

    @Test
    public void listGoesOverTheFold() {
        onView(withText("Hello World!")).check(matches(isDisplayed()));
    }

}

HelloWorldTest非常简单,就是判断”Hello World!”是不是已经显示在屏幕上

@Rule

Espresso 的API组成

  • onView()onData() 是Espresso和视图交互的入口都是用来定位一个View, onView() 是定位普通Vew, onData() 可以定位ListVew、GridView 中的一个条目
  • ViewMatchers: 实现了 Matcher<? super View> 接口,是 onView() 的参数,将它传到 onView() 中帮助定位一个View。
  • ViewActions:对一个View的动作,比如点击 click() ,可以传递给 ViewInteraction.perform() 方法
  • ViewAssertions:用来断言测试结果是否正确,可以传递给 ViewInteraction.check() 方法。

测试点击界面上的一个按钮

创建一个clickTest()测试方法,点击界面上的某个按钮

@Test
public void clickTest(){
       onView(withId(R.id.btn_click))
               .perform(click())
               .check(matches(isDisplayed()));
   }

一般情况下使用withId方法通过View的id来找到一个View,不过有时候可能不同界面中使用了相同的id,这时候可以多个条件一起使用来定位一个View,比如下面

//id为R.id.my_view text为"Hello!"的控件
onView(allOf(withId(R.id.my_view), withText("Hello!")));
//既有text "7" 又有text "item: 0"的控件
onView(allOf(withText("7"), hasSibling(withText("item: 0"))))
    .perform(click());

点击按钮,将TextView的文字由Hello World!改为Hello Espresso!,并检查结果。

app中的代码

final TextView textView = findViewById(R.id.tv_text);
findViewById(R.id.btn_click).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                textView.setText("Hello Espresso");
            }
        });

测试类中添加新的测试方法

@Test
   public void matchText(){
       //点击按钮,将Hello World!改为Hello Espresso!
       onView(withId(R.id.btn_click)).perform(click());
       //检查TextView上的文字是不是Hello Espresso!
       onView(withId(R.id.tv_text)).check(matches(withText("Hello Espresso!")));
   }

测试RecyclerView

测试RecyclerView,跳到RecyclerView的某一位置处执行点击

首先需要引入一个依赖espresso-contrib这里面包含包含 DatePicker、RecyclerView 和 Drawer 操作、无障碍功能检查以及 CountingIdlingResource

androidTestImplementation 'androidx.test.espresso:espresso-contrib:3.3.0-alpha04'

首先在应用的app中新建一个Activty来显示一个列表,接着前面的例子,在MainActivity中定义一个按钮点击进入列表页。

findViewById(R.id.btn_to_recyclerview).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                startActivity(new Intent(getApplicationContext(),RecyclerViewActivity.class));
            }
        });

测试根据position定位到某一条

新建一个RecyclerView的测试类RecyclerViewTest,测试根据position定位到某一条

@RunWith(AndroidJUnit4.class)
public class RecyclerViewTest {

    @Rule
    public ActivityTestRule<MainActivity> activityRule =
            new ActivityTestRule<>(MainActivity.class);

    @Test
    public void testRecyclerView(){
        //点击进入列表页
        onView(ViewMatchers.withId(R.id.btn_to_recyclerview)).perform(click());
        //定位到第30条并点击
        onView(ViewMatchers.withId(R.id.recyclerview))
                .perform(RecyclerViewActions.actionOnItemAtPosition(30, click()));
        //判断第30条的文字"item++++++++++++++30"是否显示了
        onView(ViewMatchers.withText("item++++++++++++++30")).check(matches(isDisplayed()));
    }
}

自定义匹配器来查找一个Item

还可以通过自定义匹配器来匹配一个Item是否存在,匹配器如下

public static Matcher<MyAdapter.ViewHolder> withAdaptedData(){
      return new TypeSafeMatcher<MyAdapter.ViewHolder>(){

          @Override
          public void describeTo(Description description) {
              description.appendText("测试item");
          }

          @Override
          protected boolean matchesSafely(MyAdapter.ViewHolder item) {
              return item.mTextView.getText().equals("item++++++++++++++30");
          }
      };
 }

通过自定义匹配器滑动到RecyclerView的相应的位置,并判断该条item是否显示

@Test
  public void matchItemData(){
      //点击进入列表页
      onView(ViewMatchers.withId(R.id.btn_to_recyclerview)).perform(click());
      //根据匹配器滑动到相应的位置
      onView(withId(R.id.recyclerview)).perform(RecyclerViewActions.scrollToHolder(withAdaptedData()));
      //判断期望的文本有没有显示
      onView(withText("item++++++++++++++30")).check(matches(isDisplayed()));
  }

Espresso-Intents

Espresso-Intents是Espresso的一个扩展,支持对被测应用发出的intent 进行验证和打桩,适用于 Android Intent,可以判断Intent是否跳转成功,传递的参数是否正确。

使用它需要添加新的依赖

androidTestImplementation 'androidx.test.espresso:espresso-intents:3.1.0'

编写Espresso-Intents之前,首先需要设置IntentsTestRule,ntentsTestRule 会在带有 @Test 注解的每个测试运行前初始化 Espresso-Intents,并在每个测试运行后释放 Espresso-Intents。

@Rule
public IntentsTestRule<MainActivity> intentsTestRule =
            new IntentsTestRule<>(MainActivity.class);

Espresso中可以使用 intended()intending() 这两个方法来验证一个Intent。

测试去一个界面选号码然后打电话的动作

app中的步骤是这样的,点击“获取号码”按钮,通过 startActivityForResult 去联系人页面选择一个号码返回保存到成员变量中,然后点击“打电话”按钮通过Intent打开系统打电话的界面。下面是测试代码:

//测试去联系人页面获取一个电话号码
@Test
public void testPickIntent(){
     //创建一个Intent用来封装返回的数据
     Intent intent = new Intent();
     intent.putExtra(ContactsActivity.KEY_PHONE_NUMBER,"123456789");
     //验证如果有相应的startActivityOnResult发生,就返回前面自己创建的结果。
     intending(IntentMatchers.hasComponent(ComponentNameMatchers.hasShortClassName(".ContactsActivity")))
         .respondWith(new Instrumentation.ActivityResult(Activity.RESULT_OK,intent));
     //点击去联系人页面的按钮
     onView(withId(R.id.btn_to_contacts)).perform(click());
     //点击打电话的按钮
     onView(withId(R.id.btn_call)).perform(click());
     //验证打电话的Intent是否发送
     intended(allOf(
             hasAction(Intent.ACTION_CALL),
             hasData("tel:123456789")
     ));
}
  • 上面的测试中, intending() 方法用来测试startActivityOnResult,当startActivityOnResult动作发生的时候,就返回自己创建的一个Intent
  • intended() 方法用来测试startActivity打开打电话页面的时候Intent的参数是否正确。

测试打开系统相机获取图片的动作

动作:一个Button,一个ImageView,点击按钮拍照,拍照确定后将图片显示到ImageView上面

@Test
 public void testTackPhoto() throws InterruptedException {
      //自定义一个拍照返回drawable图片的Intent
      Intent picIntent = new Intent();
      //把drawable放到bundle中传递
     Bundle bundle = new Bundle();
     Bitmap bitmap = BitmapFactory.decodeResource(intentsTestRule.getActivity().getResources(), R.mipmap.ic_launcher);
     bundle.putParcelable("data", bitmap);
     picIntent.putExtras(bundle);
     Instrumentation.ActivityResult result =
             new Instrumentation.ActivityResult(Activity.RESULT_OK,picIntent);
     //判断是否有包含ACTION_IMAGE_CAPTURE的Intent出现,出现就给它返回result
     intending(hasAction(MediaStore.ACTION_IMAGE_CAPTURE)).respondWith(result);

     //判断ImageView上没有显示drawable
     onView(withId(R.id.iv_take_photo)).check(matches(not(hasDrawable())));
     //点击拍照按钮去拍照界面
     onView(withId(R.id.btn_take_photo)).perform(click());
     //判断ImageView上显示了一个drawable
     onView(withId(R.id.iv_take_photo)).check(matches(hasDrawable()));
 }

 private BoundedMatcher<View, ImageView> hasDrawable(){
      return new BoundedMatcher<View, ImageView>(ImageView.class) {
          @Override
          protected boolean matchesSafely(ImageView item) {
              return item.getDrawable()!=null;
          }

          @Override
          public void describeTo(Description description) {
              description.appendText("是否有drawable");
          }
      };
 }
ACTION_IMAGE_CAPTURE

Espresso Web

Espresso Web用来测试Android中的WebView,混合应用,可以测试js和原生的交互

使用前首先引入依赖包

androidTestImplementation 'androidx.test.espresso:espresso-web:3.2.0'

下面的例子中,使用官网Demo中的本地Html页面测试,里面有javaScript相关的操作。完整demo看文末链接

简单使用:

@Test
   public void testWebViewHasDisplay(){
       //点击进入WebViewActivity
       onView(withId(R.id.btn_go_to_web)).perform(click());
       //判断页面的标题是否显示了
       onWebView().check(webMatches(Atoms.getTitle(),containsString("Hello Espresso Web")));
   }

测试JavaScript,为了支持 JavaScript 求值,被测 WebView 必须启用 JavaScript。通过 forceJavascriptEnabled() 方法来开启

@Rule
   public ActivityTestRule<WebViewActivity> activityWebRule =
           new ActivityTestRule<WebViewActivity>(WebViewActivity.class,false,false){
               @Override
               protected void afterActivityLaunched() {
                   onWebView().forceJavascriptEnabled();
               }
       };

测试:在输入框输入文字,点击某个按钮,将输入框中的文字,赋值给另一个标签。检测该标签上的文字是不是输入的文字。

@Test
public void testJsInteraction(){
    //点击进入WebViewActivity
    onView(withId(R.id.btn_go_to_web)).perform(click());
    onWebView()
            //html界面上找到id为text_input的元素
            .withElement(findElement(Locator.ID, "text_input"))
            //清除之前的文字
            .perform(DriverAtoms.clearElement())
            //输入文字Lily
            .perform(DriverAtoms.webKeys("Lily"))
            //通过id找到切换文字的按钮
            .withElement(findElement(Locator.ID, "changeTextBtn"))
            //点击按钮
            .perform(webClick())
            //通过id找到显示文字的标签
            .withElement(findElement(Locator.ID, "message"))
            //判断标签上的文字是不是Lily
            .check(webMatches(getText(), containsString("Lily")));
}

测试:在输入框中输入文字,点击提交按钮提交表单,检测表单里的值跟输入的文字是否一样

@Test
    public void testJsFormSubmit(){
        //点击进入WebViewActivity
        onView(withId(R.id.btn_go_to_web)).perform(click());
        onWebView()
                // html界面上找到id为text_input的元素
                .withElement(findElement(Locator.ID, "text_input"))
                // 清除之前的文字
                .perform(clearElement())
                // 输入文字Lily
                .perform(DriverAtoms.webKeys("Lily"))
                // 通过id找到提交按钮
                .withElement(findElement(Locator.ID, "submitBtn"))
                // 点击按钮执行提交动作
                .perform(webClick())
                // 通过id找到form表单的id
                .withElement(findElement(Locator.ID, "response"))
                // 验证提交的内容是不是Lily
                .check(webMatches(getText(), containsString("Lily")));
    }

Espresso常用的功能就练习完了,还有一些不常用的功能可以 点击去官网查看

点击查看完整demo地址


以上所述就是小编给大家介绍的《Android自动化测试入门(三)Espresso》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

微信公众号深度解析

微信公众号深度解析

魏艳 / 化学工业出版社 / 2017-5 / 49.80元

本书是一本微信公众号营销的教科书,全方位揭秘了微信订阅号、微信服务号、微信企业号三大类型账号的运营管理策略和技巧,有助于企业构建一套全新的微信公众号营销体系,打造一个移动端的商业帝国,是企业和微商必读的微信公众号营销和运营宝典。 《微信公众号深度解析:订阅号+服务号+企业号三号运营全攻略》突出了“新”、“全”、“实战”三大特点,阐述了微信公众号在新形势下的现状、发展趋势和三大类型;微信公众号......一起来看看 《微信公众号深度解析》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换