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

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

内容简介: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》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

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

The Linux Command Line

The Linux Command Line

William E. Shotts Jr. / No Starch Press, Incorporated / 2012-1-17 / USD 39.95

You've experienced the shiny, point-and-click surface of your Linux computer-now dive below and explore its depths with the power of the command line. The Linux Command Line takes you from your very ......一起来看看 《The Linux Command Line》 这本书的介绍吧!

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

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

Base64 编码/解码

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具