Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> Android開發實例 >> Android開發指南(39) —— Testing Fundamentals

Android開發指南(39) —— Testing Fundamentals

編輯:Android開發實例

前言

  本章內容為Android開發者指南的Framework Topics/Testing/Testing Fundamentals章節,版本為Android 4.0 r1,翻譯來自:"CodingMyWorld"。 

 

測試基礎

譯者署名:CodingMyWorld

譯者鏈接:http://www.cnblogs.com/codingmyworld/

版本:Android 4.0 r1

 

原文

http://developer.android.com/guide/topics/testing/testing_android.html

 

       Android測試框架作為整個開發環境不可分割的一部分,提供了一個架構和一些強大的工具,來幫助你在從單元到框架的各個水平上測試你應用的各個方面。

這個測試框架包含了以下主要特性:

* Android測試套件是基於JUnit的。你可以使用純的JUnit來測試沒有調用Android API的類,你也可以使用Android的JUnit擴展來測試Android的組件。如果你在Android測試方面還是新手,你可以先開始用諸如AndroidTestCase這樣的通用類,然後在進一步探索其他更復雜的類。

* Android的JUnit擴展提供了特定組件的測試用例類。這些類提供了創建模擬對象的幫助方法,還有幫助你控制相應組件生命周期的方法。

* 測試套件被包含在與主應用程序包類似的測試包中,因此你不需要為設計和構建測試再學習新的工具集和技術。

* 構建和測試的SDK工具在Eclipse的ADT中已經提供了,如果你使用其他的IDE,也能以命令行的形式使用。這些工具從待測應用項目中獲取信息,並利用這些信息自動的創建構建文件,清單文件,還有測試包的目錄結構。

* SDK也提供monkeyrunner,一套使用Python程序測試設備的API,還有UI/Application Exerciser Monkey,這是一個通過向設備發送偽隨機事件從而對UI進行壓力測試的命令行工具。

 

這篇文檔描述了Android測試框架的基本原理,包括測試結構,用於開發測試的API,還有你用來運行測試和查看結果的工具。此文檔假定你已經掌握了Android應用開發的基本知識和使用JUnit測試的方法。

下面這張圖總結了整個測試框架:

 

 

測試結構(Test Structure

Android的構建與測試工具設想測試項目被組織成一個標准的測試結構,及測試用例類、測試包、還有測試項目。

Android的測試是基於JUnit的。JUnit的測試大體上就是一個方法,由方法中的語句對待測試應用的某一部分進行測試。你將這些測試方法組織在一起,放到一個叫做測試用例(或者測試套件)的類中。每個測試在待測試應用的單個模塊中都是獨立的。每個測試用例類都是相關測試方法的一個容器,盡管它也提供一些幫助方法。

在JUnit中,一個或多個測試源文件被構建到class文件中;在Android中,你同樣使用SDK的構建工具將一個或多個測試源文件構建到Android測試包中的class文件裡。在JUnit中,你使用測試運行器來執行測試用例;在Android中,你使用測試工具加載測試包和待測應用,然後由工具來執行特定的Android測試運行器。

 

 

測試項目(Test Projects

測試,和Android應用程序一樣,被組織成項目。

一個測試項目是一個目錄或者Eclipse工程,你在其中創建源代碼、清單文件、還有測試包下的其他文件。Android SDK包含了為你創建和更新測試項目的工具,既有在Eclipse ADT中使用的,又有在命令行中使用的。這些工具為你創建存放源代碼和資源文件的目錄以及測試包的清單文件。命令行工具也會創建你需要的Ant構建文件。

你應該總是使用Android的工具來創建測試項目。工具還有這些好處:

* 自動設置你的測試包使用InstrumentationTestRunner作為測試用例的運行器。你必須使用InstrumentationTestRunner(或者它的子類)來運行JUnit測試。

* 為測試包創建合適的名字。如果待測試應用有一個叫做com.mydomain.myapp的包名,那麼Android工具會將測試包命名成com.mydomain.myapp.test。這幫助你辨認它們之間的關系,防止系統內的沖突。

* 自動創建恰當的構建文件、清單文件、和測試項目的目錄結構。這幫助你在構建測試包的時候無需手動修改構建文件和設置測試包與待測應用之間的聯系。

你可以在文件系統的任何地方創建測試項目,但是最佳的方式是將你的測試項目添加到主應用程序項目中,這樣測試項目的根目錄tests/就和主應用程序的src/目錄在同一個目錄層次上了。這幫助你很快的找到與應用相關的測試。例如,如果你的應用程序項目的根目錄是MyProject,那麼你應該使用如下的目錄結構:

MyProject/

      AndroidManifest.xml

      res/

          ... (主應用程序的資源)

      src/

          ... (主應用程序的代碼) ...

      tests/

          AndroidManifest.xml

          res/

              ... (測試使用的資源)

          src/

              ... (測試使用的代碼)

 

 

測試APIThe Testing API

Android測試API基於JUnit的API,並且擴展了一套儀器框架(instrumentation framework)和一些特定的Android測試類。

 

JUnit

你可以在普通的Java對象上使用JUnit的TestCase類來做單元測試。TestCase類也是AndroidTestCase類的父類,你可以使用AndroidTestCase類來測試依賴Android的對象。AndroidTestCase類除了提供JUnit框架中擁有的功能,也提供了專門在Android上使用的setup,teardown和幫助方法。

你使用JUnit中的Assert類來顯示測試結果。assert方法將你在測試中期望的結果與實際的結果作比較,並且在比較失敗的時候拋出異常。Android也提供了斷言類,它繼承了JUnit Assert類中的各種斷言類型,還提供了另一類用於測試界面的斷言。這些內容在斷言類(Assertion classes)一節中有詳細描述。

想了解更多有關JUnit的內容,你可以閱讀junit.org主頁上文檔。注意Android測試API僅支持JUnit 3的編碼風格,不支持JUnit 4。你也必須使用Android的測試運行器InstrumentationTestRunner來運行你的測試用類。測試運行器在運行測試(Running Tests)一節中探討。

 

儀器(Instrumentation

在Android系統中,儀器是指一組控制方法或者“鉤子”。這些鉤子控制著Android組件,使其獨立於它正常的生命周期。它們也控制著Android如何加載應用程序。

正常情況下,Android組件運行在由系統決定的生命周期中。比如,一個Activity對象的生命周期在它被一個Intent激活時開始,它的onCreate()方法被調用,然後是onResume()。當用戶啟動另一個應用,onPause()方法被調用。如果Activity的代碼調用了finish()方法,那麼onDestroy()方法會被調用。Android的框架API不提供讓你直接調用這些回調方法的方式,但是你可以使用儀器(instrumentation)來做這些。

同樣,系統把一個應用程序中的所有組件運行在同一個進程中。你可以允許一些組件,如content provider,運行在一個獨立的進程中,但是你不能強制一個應用程序和一個已經運行的應用程序運行在同一個進程中。

然而,有了Android儀器,你可以在測試代碼中調用那些回調方法。這讓你可以一步一步地遍歷運行一個組件的生命周期,仿佛你在調試組件。下面的代碼片段演示了如何使用儀器來測試一個Activity保存和恢復狀態:

   // 開始待測應用的主activity
   mActivity= getActivity();

 

  // 得到該activity對象一個主界面控件的句柄,一個Spinner

   mSpinner= (Spinner)mActivity.findViewById(com.android.example.spinner.R.id.Spinner01);

 

  // 設置Spinner的已知未知

   mActivity.setSpinnerPosition(TEST_STATE_DESTROY_POSITION);

 

   // 結束activity——onDestroy()方法應該保存Spinner的狀態

   mActivity.finish();

 

   // 重新啟動activity - onResume()方法應該恢復Spinner的狀態

   mActivity= getActivity();

 

  // 得到Spinner的當前位置

   int currentPosition= mActivity.getSpinnerPosition();

 

   // 斷言當前位置與啟動時的位置相同

    assertEquals(TEST_STATE_DESTROY_POSITION, currentPosition);

這裡用到的關鍵方法是getActivity(),它是儀器API的一部分。待測試的Activity直到該方法被調用的時候才會啟動。你可以提前設置一些測試配置,然後再調用該方法來啟動Activity。

同樣,儀器能將測試包和待測應用加載到同一個進程中。既然應用組件與它們的測試程序在同一個進程中,測試程序就能調用組件的方法並且修改和檢查組件中的屬性了。

 

測試用例類

Android提供了一些測試用例類,它們都繼承自TestCase類和Assert類,並帶有Android特定的setup,teardown和幫助方法。

 

AndroidTestCase

AndroidTestCase類是一個有用的通用類,特別是在你剛開始接觸Android測試的時候。它繼承了TestCase類和Assert類,提供了JUnit標准的setUp()和tearDown()方法,還有所有的JUnit裡的Assert方法。此外,它還提供了測試許可(permission)的方法和通過清除一些類引用來防止內存洩露的方法。

 

特定組件的測試用例(Component-specific test cases

Android測試框架的一個關鍵特性就是它的特定組件測試類。這些類提供了安裝(setup)和卸載(teardown)測試所需資源(fixture)的方法和控制組件生命周期的方法,解決了對特定組件進行測試的需求。它們還提供了創建模擬對象的方法。我們在特定組件測試的章節中討論這些類:

* Activity測試

* Content Provider測試

* Service測試

Android沒有為BroadcastReceiver提供一個獨立的測試用例類,取而代之的是通過向注冊BroadcastReceiver的組件發送一個intent對象,判斷broadcast receiver能否正確響應來進行測試的。

 

應用測試用例(ApplicationTestCase

你使用ApplicationTestCase類來測試Application對象的setup和teardown。這些對象維護著一個應用包中的所有組件都使用的全局狀態信息。這個測試用例在驗證清單文件中<application>元素是否被正確設置(setup)時是很有用的。但是注意該測試用例不允許你進行應用包中組件的測試。

 

儀器測試用例(InstrumentationTestCase

如果你想在測試用例中用到儀器方法,你必須使用InstrumentationTestCase類或它的一個子類。Activity測試用例繼承了該基類並實現了其他功能幫助Activity測試。

 

斷言類(Assertion classes

由於Android測試用例類繼承自JUnit,你可以使用斷言方法來顯示測試的結果。斷言方法的作用是將測試返回的實際結果同你期望的結果作比較,並在比較失敗的時候拋出AssertionException。使用斷言比記錄日志更便利,能提供更好的測試效果。

除了JUnit的Assert類方法,測試API還提供了MoreAsserts和ViewAsserts類:

* MoreAsserts類包含了更強大的斷言,比如assertContainsRegex(String, String)方法,它能夠匹配正則表達式。

* ViewAsserts類包含測試視圖時有用的斷言。例如assertHasScreenCoordinates(View, View, int, int)方法,該方法能測試一個視圖在可視屏幕特定的(X,Y)坐標處是否有位置。這些斷言方法簡化了對界面幾何形狀和對齊方式的測試。

 

模擬對象類(Mock Object classes

為了在測試中方便地使用依賴注入,Android提供了創建模擬系統對象的類,比如Context對象,ContentProvider對象,ContentResolver對象和Service對象。一些測試用例還提供了Intent模擬對象。你使用這些對象既是為了將測試與系統中的其他測試隔離開來,又能很方便的在測試中使用依賴注入。這些類能在Java包android.test和android.test.mock中找到。

模擬對象通過“屏蔽”(stub out)或重寫常規方法將測試同正在運行的系統隔離開。例如,MockContentResolver使用自己的本地框架替代常規的Resolver框架,這與系統的其他部分是隔離的。MockContentResolver也屏蔽了notifyChange(Uri, ContentObserver, boolean)方法,這樣測試環境外的觀察者對象就不會被不小心觸發了。

模擬對象還通過提供常規對象的子類來方便依賴注入,這些模擬對象並沒有實際的功能,除非你重寫了父類的方法。例如,MockResources對象是Resources的子類,裡面所有的方法在調用時都會拋出異常。使用它的時候,你只需重寫必須提供信息的方法。

下面這些是Android中可用的模擬對象:

 

簡單模擬對象類(Simple mock object classes

MockApplication,MockContext,MockContentProvider,MockCursor,MockDialogInterface,MockPackageManager和MockResources提供了簡單有用的模擬策略。他們是系統中相應對象的空實現(stubbed-out)版本,其中所有的方法在被調用的時候會拋出UnsupportedOperationException。使用它們的時候,你重寫需要的方法來依賴模擬。

注意:MockContentProvider和MockCursor是API level 8中新添的。

 

Resolver模擬對象(Resolver mock objects)

MockContentResolver通過屏蔽掉系統的常規resolver框架,提供了對content providers的隔離測試。MockContentResolver使用自己的內部表,而不是提供一個authority string去系統內部查找content provider。你必須顯示地使用addProvider(String, ContentProvider)方法為內部表增加provider。

有了這個功能,你能將一個模擬的content provider與一個authority關聯起來。你能創建一個真實provider的實例,但是僅使用其中的測試數據。你甚至可以設置一個authority的provider為null。實際上,一個MockContentResolver對象將你的測試同包含真實數據的provider隔離開來了。你可以控制provider的功能,你可以防止測試影響到真實的數據。

 

 

測試的上下文(Contexts for testing

Android提供了兩個上下文類用於測試:

*   IsolatedContext提供了一個隔離的上下文(Context),使用該上下文的文件、目錄、數據庫操作將發生在測試空間。盡管它的功能受限,該上下文還是有足夠的樁代碼(stub code)響應系統調用。

該類允許你測試應用的數據操作,而且不會影響到可能在設備上存在的真實數據。

*   RenamingDelegatingContext提供了一個上下文,其中大多數的操作都由一個已存在的上下文處理,但是文件和數據庫的操作由一個IsolatedContext處理。隔離部分使用測試目錄,並創建特殊的文件和目錄名。你可以自己控制它們的命名,或者讓構造器自動決定。

該對象提供了一種為數據操作設置隔離區的快速方式,並且保留了對其他上下文操作的常規功能。

 

 

運行測試(Running Tests

測試用例是通過測試運行器類運行的,測試運行器先加載測試用例類,然後安裝(set up)測試資源,運行測試用例,最後卸載(tear down)每個測試的資源。Android的測試運行器還必須裝上測試儀器(instrumentation),以便啟動應用的系統工具能控制測試包(test package)如何加載測試用例和待測應用程序。你通過在測試包的清單文件中設置一個值來告訴android平台使用哪個裝好儀器的測試運行器。

InstrumentationTestRunner是主要的測試運行器。它繼承了JUnit的測試運行器框架並且裝上了測試儀器。它能運行Android提供的所有測試用例類,並支持所有可能的測試種類。

你在測試包的清單文件的instrumentation元素中指定InstrumentationTestRunner或它的子類作為你的測試運行器。InstrumentationTestRunner的代碼在共享庫android.test.runner中,該庫正常情況下沒有被連接到Android代碼中。你必須在uses-library元素中指定包含它。你不需要自己手動設置這些元素,Eclipse的ADT工具和android命令行工具會在你的測試包清單文件中自動構建他們。

注意:如果你要使用別的測試運行器而不是InstrumentationTestRunner,你必須改變<instrumentation>元素,使它指向你要用的類。

你要使用被Android工具調用的內部系統類來運行InstrumentationTestRunner。當你在裝有ADT的Eclipse中運行測試時,這些類會被自動調用。當你從命令行中運行測試時,你通過Android Debug Bridge(adb)工具運行它們。

這些系統類加載和啟動測試包時,先殺死所有正在運行的待測應用的進程,然後加載待測應用的新進程。然後它們將控制交給InstrumentationTestRunner,由它來運行測試包下的每個測試用例。你還可以使用Eclipse ADT插件中的設置選項(settings)和命令行工具的標志位(flag)來控制運行哪些測試用例和方法。

待測應用既不是由系統類啟動,也不是由InstrumentationTestRunner啟動,而是由測試用例直接啟動的。測試用例既可以調用待測應用的方法,又可以調用自己的方法,這些方法能在待測應用中觸發生命周期時間的事件。待測應用在測試用例的完全控制之下,這就允許測試用例在運行測試之前設置(set up)測試環境(測試fixture)。這在先前對一個顯示Spinner控件的Activity的測試代碼段中已經演示了。

想了解更多有關運行測試的內容,請閱讀使用ADT在Eclipse中測試或者在其他IDE中測試的文章。

 

 

查看測試結果(Seeing Test Results

Android測試框架將測試結果返回到運行測試的工具上。如果你在Eclipse中使用ADT來運行測試,那麼測試結果顯示在一個新的Junit視圖窗格種。如果你從一個命令行中運行測試,那麼結果顯示在STDOUT中。在兩種情況下,你都會看到一個測試總結顯示每個測試用例的名字和其中運行的方法。你還能看到所有發生的斷言失敗,它們包括了出錯行的指針。斷言失敗還列出了期望值和實際值。

測試結果有特點的格式,這與你使用的IDE有關。使用Eclipse ADT的測試結果格式在使用ADT在Eclipse中測試中描述。使用命令行的測試結果格式在在其他IDE中測試中描述。

 

 

monkeymonkeyrunner

SDK針對功能級別的測試提供了兩個工具:

* UI/Application Exerciser Monkey,通常被叫做“monkey”,是一個向設備發送鍵盤敲擊、觸摸、手勢等偽隨機流的命令行工具。你使用Android Debug Bridge(adb)來啟動它。你使用它來對你的程序作壓力測試並報道遇到的錯誤。你可以通過每次使用相同的隨機數種子啟動該工具來重復一個事件流。

* monkeyrunner工具是使用Python來測試程序的一套API和執行環境。這套API包括了連接設備、安裝和卸載應用包、截屏、比較兩幅圖片和運行測試應用測試包的功能。有了monkeyrunner命令行工具提供的這套API,你可以寫出大型的、強大的、復雜的測試。

 

 

使用包名工作(Working With Package names

在測試環境中,你會同時遇到Android應用程序的包名和Java的包名。這兩個包名的命名格式相同,但它們實質上代表了不同的實體。你需要知道這些不同來幫助你正確地設置你的測試。

Android的包名是一個.apk文件獨一無二的系統名,它由包內清單文件中的<manifest>元素的"android:package"屬性設置。你測試包的Android包名必須和待測應用的包名不同。默認情況下,Android工具在待測應用包名的後面加上".test"來作為測試包名。

測試包同樣使用Android包名來找到它所測試的應用程序包。這是在測試包清單文件的<instrumentation>元素的"android:targetPackage"屬性上設置的。

Java的包名符適用於源文件。這個包名反映了源文件的目錄路徑。它也影響著類之間、成員之間的可見性。

創建測試項目的Android工具為你設置Android測試包的包名。工具會根據你的輸入來設置測試包的包名和待測應用的包名。要想讓這些工具工作,必須已經有應用項目了。

默認情況下,這些工具把測試類的Java包名與測試包的Android包名設置成一樣的。如果你想要給它們包可見性,從而在待測應用中暴露出一些成員,你可能需要做些改動。假如你真要這麼做了,請你只改動Java的包名,不要改動Android包名,並且只改變測試用例類的源文件。不要改變在你測試包中生成的R.java類的Java包名。不要將測試包的Android包名改成與待測應用的Android包名一樣,因為這樣的話系統中的Android包名就不是唯一的了。

 

 

測試什麼(What to Test

測試什麼一章討論了你應該在Android應用程序中測試的關鍵功能和可能影響功能的關鍵情形。

大多數單元測試都特定在你正在測試的Android組件上。Activity Testing,Content Provider Testing和Service Testing每一篇都有題為“測試什麼”的小節,列出了可能的測試范圍。

可能的話,你應該在真實設備上運行這些測試。不可能的話,你可以使用針對你所測試的硬件、屏幕、版本配置的Android虛擬設備的Android模擬器。

 

 

下一步

學習如何在Eclipse中運行測試,請參考使用ADT在Eclipse中測試。如果你不使用Eclipse工作,請參考在其他IDE中測試。

如果你想要一個對Android測試的一步一步地介紹,嘗試一篇測試教程或者示例測試包:

* Hello, Testing教程介紹了在Hello,World應用上下文中的基本測試概念和步驟。

* Activity Testing教程是Hello,Testing教程的一個很好的後續。它指導你在開發一個更加實際的應用時應該如何完成一個復雜的測試場景。

 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved