qileilove

          blog已經轉移至github,大家請訪問 http://qaseven.github.io/

          Android自動化追本溯源系列(1):獲取頁面元素

            本系列旨在闡述Android自動化的原理,讓大家明白如何在Android平臺上做自動化,甚至開發出自己的自動化工具來。

            什么是Android自動化?

            相信對于測試同 學,這個問題就很簡單了。自動化的目的就是做好回歸測試,以達到版本控制,并節省人力。而Android自動化就是在Android平臺上做測試自動化, 相信隨著Android開發的日趨盛行,其測試自動化的需求也會逐漸增強,知其然,固然是好,但如能知其所以然,必將錦上添花。

            目前我所知道的做Android自動化的工具有:

            ● Ranorex 支持錄制回放功能,但是不太好用,需要在開發代碼中注入一段測試代碼,并且它是收費的。

            ● Robotium 開源的黑盒測試框架,使用時需要引入一個JAR包,需要測試人員有一定的編碼功底,才能編寫Test Case。

            ● Monkeyrunner Google隨SDK發布的測試工具,功能簡單,不是很好用。

            因為是想研究自動化原理,所以這里主要參考Robotium以及Android源碼。

            如何識別頁面元素?

            做過自動化的同學應該都知道,我們在寫涉及UI的自動化case時,其基本思路就是找到某元素—>執行操作,這里的操作要么是動作,要么是是驗證。仔細想想,其實道理就是這樣。所以說如果我們想開發自己的自動化測試工具時,首要解決的問題就是,如何在測試時,找到頁面的元素。

            而在Android中,思路也是一樣。

             如何大家研究過Android的窗口機制的話,應該看到過這樣的說法,真正實現WindowManager窗口機制的是 WindowManagerImpl類,它會把DecorView添加到mViews數組,創建對應的ViewRoot,而DecorView是何物呢? 參考我上篇博客:http://www.cnblogs.com/jinsdu/archive/2013/01/03/2840565.html 知道,實際上DecorView是頁面最頂層的View,而如果能夠獲取到它,我們就可以將其轉換成ViewGroup,然后遍歷其所有子節點從而得到所 有的頁面元素了。而運用java的反射機制,正好可以在運行時,獲取類的屬性和方法:

            于是在運行時,獲得WindowManagerImpl類:

          private static Class<?> windowManager;
              static{
                  try {
                      String windowManagerClassName = "android.view.WindowManagerImpl";
                       windowManager = Class.forName(windowManagerClassName);
                  } catch (ClassNotFoundException e) {
                      throw new RuntimeException(e);
                  } catch (SecurityException e) {
                      e.printStackTrace();
                  }
              }

            然后獲得頁面的DecorView:

          private View[] getWindowDecorViews()
              {

                  Field viewsField;
                  Field instanceField;
                  try {
                      viewsField = windowManager.getDeclaredField("mViews");
                      instanceField = windowManager.getDeclaredField("sWindowManager");
                      viewsField.setAccessible(true);
                      instanceField.setAccessible(true);
                      Object instance = instanceField.get(null);
                      return (View[]) viewsField.get(instance);
                  } catch (SecurityException e) {
                      e.printStackTrace();
                  } catch (NoSuchFieldException e) {
                      e.printStackTrace();
                  } catch (IllegalArgumentException e) {
                      e.printStackTrace();
                  } catch (IllegalAccessException e) {
                      e.printStackTrace();
                  }
                  return null;
              }

           如此我們就獲得了頁面的DecorView了,轉換成ViewGroup,遍歷其所有子元素,我們就能獲得頁面的所有元素:

          public ArrayList<View> getAllViews() {
                  final View[] views = getWindowDecorViews();
                  final ArrayList<View> allViews = new ArrayList<View>();

                  if (views != null && views.length > 0) {
                      View view;
                      for (int i = 0; i < views.length; i++) {
                          view = views[i];
                    allViews.add(view);
                          getAllChildren(allViews, (ViewGroup) view);
                      }
                  }
                  return allViews;
              }

              private void getAllChildren(ArrayList<View> allViews, ViewGroup viewGroup) {
                  if (viewGroup != null) {
                      for (int i = 0; i < viewGroup.getChildCount(); i++) {
                          View child = viewGroup.getChildAt(i);
                          allViews.add(child);
                          if (child instanceof ViewGroup) {
                              getAllChildren(allViews, (ViewGroup) child);
                          }
                      }
                  }
              }

            而獲得了頁面的元素,就基本上完成了我們UI Automation兩步走的第一步 —> 找到頁面元素。試想一下,如果我們的Android自動化框架有上面類似的功能,那么我們的自動化框架就能在運行時獲得頁面的所有元素,而我們在寫 case時,也許只要傳給自動化框架一個控件ID,我們就可以獲得這個元素了。有了這個元素我們就可以向我們的第二步邁進了—>在控件上執行操作, 或者取其屬性進行Expected驗證。當然我會在接下來的文章中,一一闡述這些內容。

            總結

            研究Android自動化原理,要涉及到很多知識,尤其對Android的窗口機制要更加明確,像頁面是如何加載,如何通信,都不是一言半語可 以說清的,我也是正在研究中。對于WindowManagerImpl類的源碼,有興趣的同學,可以研究下:http://grepcode.com /file/repository.grepcode.com/java/ext/com.google.android/android/4.1.1_r1/android/view/WindowManagerImpl.java#WindowManagerImpl

            最后,欲知后事如何,且聽下回分解。

          posted on 2013-05-17 10:20 順其自然EVO 閱讀(409) 評論(1)  編輯  收藏 所屬分類: android

          評論

          # re: Android自動化追本溯源系列(1):獲取頁面元素 2013-05-17 12:45 開發吧

          這篇文章我好像以前看過了,忘了,不過溫故而知新,支持!  回復  更多評論   

          <2013年5月>
          2829301234
          567891011
          12131415161718
          19202122232425
          2627282930311
          2345678

          導航

          統計

          常用鏈接

          留言簿(55)

          隨筆分類

          隨筆檔案

          文章分類

          文章檔案

          搜索

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 巴中市| 哈密市| 腾冲县| 大悟县| 武夷山市| 鄂尔多斯市| 太和县| 稻城县| 临朐县| 鹿邑县| 华阴市| 延边| 公主岭市| 安图县| 尚义县| 泊头市| 额济纳旗| 旌德县| 驻马店市| 开封市| 清苑县| 泾阳县| 衡山县| 普洱| 城口县| 新乡市| 永清县| 剑阁县| 建昌县| 花垣县| 天长市| 江孜县| 华安县| 嘉禾县| 札达县| 武山县| 扬中市| 屏南县| 怀集县| 武冈市| 潢川县|