天天看點

Android開源測試架構學習

Android測試大緻分三大塊:

  1. 代碼層測試
  2. 使用者操作模拟,功能測試
  3. 安裝部署及穩定性測試

對于一般java代碼,采用傳統的Junit測試,開發人員通常會編寫重要接口和函數的白盒測試代碼,不做過多讨論。

但因Android的特殊運作機制(Dalvik虛拟機),其中存在Application、Activity、Service等特殊元件,而這些元件都涉及到生命周期管理的問題。

為了對這些元件進行測試,Google提供了一套針對性的測試架構,AndroidTestFramework

官方教程連結 http://developer.android.com/training/testing.html

官方api http://developer.android.com/reference/android/test/package-summary.html

其中最為常用的就是針對Activity的測試,即ActivityInstrumentationTestCase2<T>類。

繼承該類後可通過getActivity()方法擷取Activity的一個mock對象,進而實作各種界面元素的測試。代碼如下

public class LoginActivityTest extends ActivityInstrumentationTestCase2<LoginActivity> {
        LoginActivityTest mActivity;
        Button btnLogin;        public LoginActivityTest(){      super(LoginActivity.class);//必須實作super(testclass)        }
    
    @Override    protected void setUp() throws Exception {        super.setUp();
        mActivity = getActivity();
                btnLogin = mActivity.findViewById(R.id.btnLogin);
    }        public void testGetActivity(){
           assertNotNull("can't get LoginActivity" , mActivity);
           assertNotNull("can't get loginButton" , btnLogin);
        }
}      

需要注意的是,測試代碼運作的線程并不是UI線程。是以如果需要對UI元素進行setText或是click之類的操作,需要通過getActivity().runOnUiThread(action)方法執行。代碼如下

getActivity().runOnUiThread(new Runnable() {
            @Override            public void run() {
                 btnLogin.click();
            }
        });      

雖然AndroidTestFramework可以幫助我們完成各種界面的測試。但是,這些代碼的編寫非常繁瑣。而且在大部分情況下,我們需要的是一個連貫性的,在多個Activity之間存在跳轉的業務流程測試。這種測試比較接近傳統的白盒測試,隻針對可見的UI元素進行操作,模拟使用者的行為來完成測試。

Google同樣為我們提供了一套專門針對UI元素的測試方案,具體可見http://developer.android.com/tools/testing/testing_ui.html

可是Google的這套UI架構仍然不是很友好。為此,我尋找了一些相對成熟的測試架構來幫助我們。經過一系列分析比較和實際代碼測試,在這推薦采用Robotium開源架構做為今後一段時間内的主要業務測試架構。

Robotium介紹

Robotium是一款國外的Android自動化測試架構,主要針對Android平台的應用進行黑盒自動化測試,它提供了模拟各種手勢操作(點選、長按、滑動等)、查找和斷言機制的API,能夠對各種控件進行操作。Robotium結合Android官方提供的測試架構達到對應用程式進行自動化的測試。另外,Robotium 4.0版本已經支援對WebView的操作。Robotium 對Activity,Dialog,Toast,Menu 都是支援的。

源碼及相關資料位址:https://code.google.com/p/robotium/

Robotium具有清晰的調用方法、良好的相容性、完善的文檔和大量的實際應用案例,并且支援截屏。最為符合我們目前的實際需求。經實際測試,無需特殊配置即可相容Jenkins系統。

下面以一段HSA項目中的實際測試代碼舉例。該測試用例完成從登陸、菜單選取、一直到功能界面輸入驗證的一個流程。

public class LoginActivityTest extends ActivityInstrumentationTestCase2<LoginActivity> {
    Solo solo;
    LoginActivity mActivity;    
    public LoginActivityTest(){        super(LoginActivity.class);
    }
    
    @Override    protected void setUp() throws Exception {        super.setUp();

        mActivity = getActivity();//初始LoginActivity
        solo = new Solo(getInstrumentation(),mActivity);//初始Robotium的主要入口,solo對象    }    
    public void testLogin(){        //清除使用者名EditText内容
        solo.clearEditText(0);        //輸入"userName" 到使用者名EditText
        solo.enterText(0, "userName");        
        //清除密碼EditText内容
        solo.clearEditText(1);        //輸入"userPass" 到密碼EditText
        solo.enterText(1, "userPass");        
        //清除站點EditText内容
        solo.clearEditText(2);        //輸入"siteCode" 到站點EditText
        solo.enterText(2, "siteCode");        
        //點選登陸按鈕
        solo.clickOnButton("登入");        
        //檢驗目前界面為MainListActivity
        solo.assertCurrentActivity("Expected MainListActivity activity", "MainListActivity");        
        //點選動态菜單清單中的第一項,進入下一級子菜單界面
        solo.clickInList(0);        //檢驗目前界面為SubMenuActivity
        solo.assertCurrentActivity("Expected SubMenuActivity activity", "SubMenuActivity");        
        //點選子菜單清單中的第一項,進入功能界面
        solo.clickInList(0);        //檢驗目前界面為ReceiveActivity
        solo.assertCurrentActivity("Expected ReceiveActivity activity", "ReceiveActivity");        
        //點選界面中的"使用目前人員"按鈕
        solo.clickOnButton("使用目前人員");        //輸入重量
        solo.enterText(1, "123");        
        //輸入單号
        solo.enterText(2, "21123456798");        
        //模拟軟鍵盤,發送EditText的ACTION_DONE事件
        solo.getCurrentActivity().runOnUiThread(new Runnable() {
            @Override            public void run() {
                solo.getEditText(2).onEditorAction(EditorInfo.IME_ACTION_DONE);
            }
        });        
        //尋找是否有内容為"已掃描1件"的textview, 會自動等待10秒
        boolean succ = solo.searchText("已掃描1件"))        
        //判斷成功        assertTrue(succ);
    }
}      

可見,Robotium通過一個solo對象來進行各種事件的模拟,代碼清晰易懂,并且完全相容原生AndroidTestFramework

安卓系統最為讓人诟病的問題就是碎片化,這點在中國比較明顯。大緻上,2.3.X 和 4.x 的系統各占半壁江山,此外還存在大量的山寨定制系統。

是以在這推薦兩款雲端測試工具,Testin和百度雲測試。

兩個架構測試都很簡單,在官網新增賬號後上傳apk即可,網站會用大量的真機進行安裝部署和monkey測試。測試完成後會發送一份測試給注冊郵箱。

Testin支援Robotium架構的代碼測試,同時上傳項目apk和測試apk(相同簽名)即可。

Testin位址: http://www.testin.cn/

百度雲測試: http://mtc.baidu.com/

其他測試架構

Monkey測試

Android SDK開發包中自帶一個monkeyrunner的工具,可用來進行monkey測試。

文檔位址:

  • http://developer.android.com/tools/help/monkeyrunner_concepts.html
  • http://developer.android.com/tools/help/monkey.html

Robolectric

一款基于JVM運作的Android測試架構,最大特點就是不需要啟動模拟器,是以速度非常快!

目前已支援大部分原生SDK功能的測試,支援Resource,但對于一些特殊硬體上的模拟還存在欠缺。期待進一步的完善

示例代碼:

// Test class for MyActivity@RunWith(RobolectricTestRunner.class)public class MyActivityTest {

  @Test  public void clickingButton_shouldChangeResultsViewText() throws Exception {
    Activity activity = Robolectric.buildActivity(MyActivity.class).create().get();

    Button pressMeButton = (Button) activity.findViewById(R.id.press_me_button);
    TextView results = (TextView) activity.findViewById(R.id.results_text_view);

    pressMeButton.performClick();
    String resultsText = results.getText().toString();
    assertThat(resultsText, equalTo("Testing Android Rocks!"));
  }
}      

位址: http://robolectric.org/index.html

Google Espresso

Google于2013年10月開源的一款測試架構。據稱在Google内部已認證多個項目的實際驗證,并可能在未來加入到預設AndroidSDK中。

設計上接近Robotium,主要用于業務端的模拟行為測試。相較Robotium,具有更為強大的UI元素比對尋找功能和更快的運作速度。

不過經過本人的實際使用,發現該架構的代碼編寫相對複雜,遠不如Robotium來的輕巧。此外,該架構無法運作在預設AndroidTestFramework中(可認為是更新版),且因剛開源,缺少文檔和應用案例等資料,導緻測試代碼編寫效率相對低下,故暫時不予采用。

位址: https://code.google.com/p/android-test-kit/wiki/Espresso

Mockito

一款用于Mock測試的主流架構

位址: https://code.google.com/p/mockito/

  List mockedList = mock(List.class);
  when(mockedList.get(0)).thenReturn("first");
  System.out.println(mockedList.get(0));      

總結

如無意外,接下來一段時間内,Android項目會采用以下的方案搭建測試架構:

  • 代碼級: AndroidTestFramework + Junit
  • UI業務模拟: Robotium
  • 安裝部署: Testin

繼續閱讀