你有多久没有写单元测试了(二)

发表于:2017-8-24 15:32

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:ZoranLee    来源:51Testing软件测试网采编

  [toc]
  上一篇说道如何在AndroidStudio中配置Espresso,本篇主要介绍使用Espresso时的思考和示例(示例已托管在github);
  关于Espresso的一些杂谈
  Espresso被习惯的成为浓缩咖啡,据说原发明国是意大利。不知道为啥Google要将这么有灵魂的测试框架取名叫浓缩咖啡,"浓缩的就是精华"?:)。
  愿景
  愿你沉醉在单元测试中日渐消瘦,无法自拔~
  愿你归来时,仍是少年。
  对Espresso的基本印象
  其实在Android 测试支持库中就已经包括如下的一些自动化测试工具:
  AndroidJUnitRunner:适用于 Android 且与 JUnit 4 兼容的测试运行器
  Espresso:UI 测试框架;适合应用中的功能性 UI 测试
  UI Automator:UI 测试框架;适合跨系统和已安装应用的跨应用功能性 UI 测试
  Espresso 测试框架提供了一组 API 来构建 UI 测试,用于测试应用中的用户流。利用这些 API,可以编写简洁、运行可靠的自动化 UI 测试。
  Espresso 测试框架的主要功能
  视图匹配
  操作 API
  UI 线程同步
  系好安全带,开车了
  单一特性查找控件
  现在有这么一个情况,代码刚写完,迫不及待的想看一下里边的控件(视图)表现是否得体。
  怎么能设计一个套路,来检测一下?
  首先,得找到你想找的控件(视图)。
  那么问题来了,茫茫人海,一叶扁舟,怎么才能找到想要的控件(视图)?
  俗话说:“*****,捉贼拿脏”,先找一下控件的特征:)
  ●onView(withId(R.id. jack)) 【在知道控件id的情况下】
  ●onView(withText("Jack"))【有文本"Jack"这几个字的文本控件】
  ●onView(withTagKey("full_name"));【根据setTag(key,value)来查找】
  ●onView(withTagValue("Jack_Dawson"));【Jack的全名叫杰克.道森,tag的值】
  ●onView(withHint("提示词")); 【忘词了,居然有提示词 eg.EditText】
  ….
  and so on 可以根据指定的特征来对控件进行筛选查找【文末的附图有详细的介绍】
  多个特性查找控件
  但是,有时候我们会遇到这种情况:
  多个页面中控件的id是一样的,这个时候就要需要根据多个特性来筛选了。
  毫无疑问,一个惊天地、泣鬼神的API就要出世了。不错,它就是智慧与美貌并存,正义与侠义的化身的 allof()
  在Matchers类下边有一个方法allOf(),参数是一个可变参数,我的个乖乖,这样以上的单一的特性就可以,添加多特性筛选了;
  具体示例如下:
  onView(allOf(withId(R.id.jack),withText("Jack")));[注:可变参数可以传递多个参数]
  一个ID叫jack,并且显示了“Jack”文字的控件,当然可以加很多限制条件,只有你有都可以传递在allOf的可变参数中
  至此,在Espresso中查找一个控件不在是难事了:)
  东风已借,完事具备,开测了、开测了!
  show me the code!
  测RecyclerView引发的血案
  public class RecyclerViewTest extends ActivityInstrumentationTestCase2<RecyclerViewActivity> {
      private static final String BOOK_TITLE = "Clean Code";
      private static final String BOOK_AUTHOR = "Robert C. Martin";
      public RecyclerViewTest() {
          super(RecyclerViewActivity.class);
      }
      @Override
      protected void setUp() throws Exception {
          super.setUp();
          getActivity();//设置运行上下文
      }
     
      //RecyclerViewActions为Espresso的提供API
      /**
       * 根据Item的position来进行测试
       */
      public void testClickAtPosition() {        
     onView(withId(R.id.recyclerView)).perform(RecyclerViewActions.actionOnItemAtPosition(0,  click()));//点击RecyclerView的第一个条目
          onView(withId(R.id.book_title)).check(matches(withText(BOOK_TITLE)));//检查控件文本内容是否和BOOK_TITLE内容一致
          onView(withId(R.id.book_author)).check(matches(withText(BOOK_AUTHOR)));//同上
      }
      public void testClickOnViewInRow() {
          //点击一个有具体描述的文本
          onView(withId(R.id.recyclerView)).perform(RecyclerViewActions.actionOnItem(
                  hasDescendant(withText(BOOK_TITLE)), click()));//
          onView(withId(R.id.book_title)).check(matches(withText(BOOK_TITLE)));
      }
  }
  附:
  1.RecyclerViewActivity
  public class RecyclerViewActivity extends AppCompatActivity {
      @Override
      protected void onCreate(Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);
          setContentView(R.layout.activity_recycler_view);
          RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recyclerView);
          recyclerView.setLayoutManager(new LinearLayoutManager(this));
          recyclerView.setAdapter(new RecyclerBooksAdapter(this));
      }
  }
  2.item_book.xml
  <?xml version="1.0" encoding="utf-8"?>
  <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
      xmlns:tools="http://schemas.android.com/tools"
      android:orientation="vertical"
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      android:padding="12dp">
      <ImageView
          android:id="@+id/icon"
          android:src="@drawable/book"
          android:layout_width="40dp"
          android:layout_height="40dp"
          android:layout_marginRight="8dp" />
      <TextView
          android:id="@+id/book_title"
          android:layout_toRightOf="@id/icon"
          android:layout_toEndOf="@id/icon"
          android:layout_width="fill_parent"
          android:layout_height="wrap_content"
          android:textSize="16sp"
          tools:text="Some Cool Book" />
      <TextView
          android:id="@+id/book_author"
          android:layout_below="@id/book_title"
          android:layout_toRightOf="@id/icon"
          android:layout_toEndOf="@id/icon"
          android:layout_width="fill_parent"
          android:layout_height="wrap_content"
          android:textSize="12sp"
          tools:text="by Awesome Author" />
  </RelativeLayout>
  由一句话引发的思考
  onView(withId(R.id.recyclerView)).perform(RecyclerViewActions.actionOnItemAtPosition(0,  click()));
  关于perform()函数的二三事:
  一眼就能看出,能使用perform函数的都是演员;演员是那些控件(View),现在,编剧是你,导演是你,看你想这个演员(控件|View)怎么演了。
  perform的传参:可变参数,对,你没看错,还是可变参数。这就意味着,你可以让演员演一系列的动作(Action|ViewAction)。然鹅,还是要对表演的套路做一些了解的,且看一下ViewAction的基本套路。
  ViewAction中都有哪些动作呢?
  clearText()清空文本
  click()点击动作
  swipe系列 [猛击,这个厉害了]
  swipeLeft()       原版解释:swipe right-to-left across the vertical center of the view
  swipeRight()    原版解释:swipe left-to-right across the vertical center of the view
  swipeDown()       原版解释:       top-to-bottom
  swipeUp()       原版解释:       bottom-to-top 
  closeSoftKeyboard() 这个不用多说了吧,关闭软键盘
  pressBack() 相当于点击了返回键了
  pressKey(keyCode)  还可以根据keycode来点击按键
  doubleClick() 双击
  longClick()
  等一系列操作,限于篇幅就不在过多的展开了,想看详细的可以直接去ViewAction类下边去看,只有你想不到的没有你看不到的~
  后话:其他的Action多多少少和ViewAction有一些说不清道不明的关系,相当之暧昧,比如:RecyclerViewActions、EditorAction、CloseKeyboardAction、ScrollToAction等,有兴趣的可以看一下它们的实现
  check()函数的二三事
  演员演完了,这时候作为导演就得看一下演员演的是否到位,关键是否达到了预期的效果,如果你要加点潜规则啥的都看你自己了:)
  来定义一点规则吧,不然演员就瞎演了。
  ●check函数的传参ViewAssertion(Checks the state of the given view (if such a view is present).)【大佬们的命名真腻害,这不就是对这个控件的断言吗?】
  那么问题来了,check到底能检查一些什么信息?且听我细细道来。
  先举个简单的例子吧:
  onView(withId(R.id.jack)).check(matches(isDisplayed()));//检查控件是否显示了
  onView(withId(R.id.jack)).check(matches(not(isDisplayed()));//not
  onView(withId(R.id.jack)).check(matches(withHint("Jack")));//检查提示词是否正确
  onView(withId(R.id.jack)).check(matches(withText("Jack")));//检查文本
  当然还有很多可以检测的类型,例如isEnabled()、isFocusable()、hasFocus()等等
  所有的可检测的类型都在ViewMatchers类里边了,想了解的少年可以去瞅瞅
  【附】
  ●示例传送门
  https://github.com/ZoranLi/EspressoExample github地址
  ●附图
  image.png
相关文章链接:
你有多久没有写单元测试了(一)


《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号