Android單元測試介紹

jopen 8年前發布 | 68K 次閱讀 Android開發 移動開發

 Android的測試支持庫為測試Android應用提供了大量框架。該庫提供了一組API快速構建和運行測試代碼,包括JUnit4和功能用戶界面(UI)測試。可以從Android Studio IDE中或命令行這執行。

Android的測試支持庫可通過Android SDK管理器獲取。

測試支持庫特性

AndroidJUnitRunner:兼容JUnit 4測試運行器。 Espresso:UI測試框架;適合在單個應用的功能UI測試。 UI Automator:UI測試框架;適用于跨應用的功能UI測試及安裝應用。

AndroidJUnitRunner

AndroidJUnitRunner類是JUnit測試運行器,可以讓你在Android設備上執行JUnit3或JUnit4中風格的測試類,兼容Espresso和UI Automator測試框架。測試運行器加載測試包和應用,運行測試并報告測試結果。該類取代 InstrumentationTestRunner類(僅支持JUnit 3)。

這個運行器的主要特點:

  • JUnit支持

  • 獲得Instrumentation信息

  • 測試篩選

  • 測試分片

要求的Android2.2(API 8)或更高。

 

測試運行器兼容JUnit3和JUnit4的(最高JUnit4.10)測試。在同一個包混淆JUnit 3和和JUnit4測試代碼可能會導致不可預測的結果。instrumented JUnit 4測試類在設備或仿真器上運行,必須在前面加上@RunWith(AndroidJUnit4.class)注釋。

 

比如測試CalculatorActivity類中的加操作:

 

import android.support.test.runner.AndroidJUnit4;
import android.support.test.runner.AndroidJUnitRunner;
import android.test.ActivityInstrumentationTestCase2;

@RunWith(AndroidJUnit4.class)
public class CalculatorInstrumentationTest
        extends ActivityInstrumentationTestCase2<CalculatorActivity> {
        
    @Before
    public void setUp() throws Exception {
        super.setUp();
        
        // Injecting the Instrumentation instance is required
        // for your test to run with AndroidJUnitRunner.
        injectInstrumentation(InstrumentationRegistry.getInstrumentation());
        mActivity = getActivity();
    }
    
    @Test
    public void typeOperandsAndPerformAddOperation() {
        // Call the CalculatorActivity add() method and pass in some operand values, then
        // check that the expected value is returned.
    }
    
    @After
    public void tearDown() throws Exception {
        super.tearDown();
    }
}

InstrumentationRegistry類可以訪問測試運行的信息。該類包括Instrumentation對象,目標應用上下文對象,測試應用上下文對象及傳遞到測試的命令行參數。

JUnit 4.x的測試可以使用annotation來配置測試運行,并支持Androidannotation:

@RequiresDevice:物理設備上運行。

@SdkSupress:限定最低SDK版本。例如@SDKSupress(minSdkVersion=18)
@SmallTest,@MediumTest和@LargeTest:測試分級。

單個test suite可以分片,同一Instrumentation的同一分片可以作為一個組。每個片都有索引號。當運行測試,使用-e numShards選項指定片數和-e shardIndex選項來指定要運行的片。

例如分成10個碎片,僅執行第二片測試,請使用以下命令:

adb shell am instrument -w -e numShards 10 -e shardIndex 2

Espresso

Espresso提供了一組API來構建UI測試來測試用戶流程。這些API讓你寫簡潔和可靠運行的自動化UI測試。Espresso非常適合白盒自動測試,測試代碼利用了被測應用的代碼細節。

Espresso的主要特性:

  • 視圖匹配(View matching): 靈活的API用于查看和適配目標應用。

  • Action API:一套擴展的action API自動化UI交互。

  • UI線程同步(UI thread synchronization)以提高測試的可靠性。

要求Android2.2(API 8)或更高。

Espresso.onView()方法可以訪問目標應用程序的UI組件并與之交互。該方法接受一個Matcher參數,搜索視圖層來定位視圖實例。定位方法可以基于類名、內容描述、R.id、顯示的文本。比如

onView(withId(R.id.my_button));


如果搜索成功,onView()方法返回對應view的引用,可執行用戶操作和斷言。

AdapterView由子view動態生成。如果目標視圖在AdapterView(ListView或GridView)中,onView()方法可能不起作用,因為可能只加載了一部分,Espresso.onData()則可以。

ViewActions可以執行視圖點擊(View clicks),滑動(Swipes),按鍵或者按鈕(Key and button press)、文本輸入(Typing text)、打開鏈接(Opening a link)。

// Type text into an EditText view, then close the soft keyboard
onView(withId(R.id.editTextUserInput))
    .perform(typeText(STRING_TO_BE_TYPED), closeSoftKeyboard());
// Press the button to submit the text change
onView(withId(R.id.changeTextBt)).perform(click());

由于時間問題,在Android設備上測試隨機失敗。之前一般通過sleep和超時處理解決。Espresso測試框架處理Instrumentation和UI線程之間的同步,很好地解決了這些問題。

API參考:developer.android.com/reference/android/support/test/package-summary.html
測試參考:http://developer.android.com/training/testing/ui-testing/espresso-testing.html

 

UI Automator

UI Automator提供了一組API來構建基于交互UI的測試。API允許你執行操作,如打開設置菜單,非常適合黑盒自動化測試,測試代碼不依賴于應用的內部實現。

主要特性:

  • UI Automator Viewer:檢查的布局層次。

  • API來獲取設備狀態信息并執行操作。

  • API跨應用測試。

要求Android4.3(API等級18)或者更高。

uiautomatorviewer提供了一個方便的圖形用戶界面進行掃描和分析在Android設備上當前顯示的UI組件。您可以使用此工具來檢查的布局層次和查看UI組件。

UiDevice 類可以訪問設備并進行操作。你可以調用它的方法來訪問設備屬性,如當前的方向或顯示尺寸。該UiDevice類也讓您執行操作,例如:旋轉設備;按下D- pad按鈕;按Back、Home、Menu等;打開通知樹欄;當前窗口截圖等。比如按Home鍵:UiDevice.pressHome()。

更 多應用相關的API: UiCollection枚舉容器的UI元素以計數,或通過文字(或屬性等)定位子元素; UIObject表示是在設備上可見的UI元素; UiScrollable:為可滾動UI容器提供查找支持; UiSelector:查詢一個或者多個UI元素; Configurator: 設置參數。比如:

// Initialize UiDevice instance
mDevice = UiDevice.getInstance(getInstrumentation());
// Perform a short press on the HOME button
mDevice().pressHome();
// Bring up the default launcher by searching for
// a UI component that matches the content-description for the launcher button
UiObject allAppsButton = mDevice
        .findObject(new UiSelector().description("Apps"));
// Perform a click on the button to bring up the launcher
allAppsButton.clickAndWaitForNewWindow();

API參考:http://developer.android.com/reference/android/support/test/package-summary.html
實例:http://developer.android.com/training/testing/ui-testing/uiautomator-testing.html

https://pypi.python.org/pypi/uiautomator 用python封裝了uiautomator,操作起來更簡單,推薦使用。

 

測試支持庫安裝

android {
    defaultConfig {
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
}

 

  • 啟動Android SDK管理器。

  • 在SDK管理器窗口,滾動到軟件包列表的末尾,找到其他文件夾,如有必要,展開以顯示其內容。

  • 選擇 Android Support Repository。

  • 點擊Install packages。

    下載后安裝支持庫文件到您現有的Android SDK目錄。該庫文件位于你的SDK的子目錄:<sdk>/extras/android/m2repository。

    Android的測試支持庫位于android.support.test包。

    Gradle中使用:build.gradle文件中添加這些依賴關系:


    dependencies {
      androidTestCompile 'com.android.support.test:runner:0.4'
      // Set this dependency to use JUnit 4 rules
      androidTestCompile 'com.android.support.test:rules:0.4'
      // Set this dependency to build and run Espresso tests
      androidTestCompile 'com.android.support.test.espresso:espresso-core:2.2.1'
      // Set this dependency to build and run UI Automator tests
      androidTestCompile 'com.android.support.test.uiautomator:uiautomator-v18:2.1.2'
    }



    設置AndroidJUnitRunner為默認測試:
    強烈建議您一起使用Android測試支持庫與Android Studio IDE。 Android的Studio支持測試開發,如:

        基于Gradle的靈活的構建系統,支持測試代碼的依賴管理。
        單個項目包含應用程序源代碼和測試代碼。
        支持虛擬或物理設備的部署和運行測試,支持命令行或圖形用戶界面

    更多介紹參見:http://developer.android.com/sdk/index.html

參考資料

  • Testing Support Library

  • http://wiki.jikexueyuan.com/project/android-weekly/issue-145/android-ui-auto-testing.html

  • http://developer.android.com/intl/zh-cn/training/testing/ui-testing/espresso-testing.html

  • http://www.stevenmarkford.com/android-ui-testing-with-espresso-basics-tutorial/

  • http://www.csdn.net/article/2015-08-19/2825493-using-espresso-for-easy-ui-testing

 

作者博客:http://my.oschina.net/u/1433482/ python測試開發精華群 291184506 PythonJava單元白盒測試 144081101

Android測試基礎

android測試框架(Android Testing Framework)是開發環境的一部分,它提供了架構和強大的工具幫助你從單元到框架測試應用的各個方面。

本部分有點偏舊,如果和其他部分內容有沖突,以其他內容為準。


關鍵特性:

  • 基 于 JUnit,可直接使用JUnit測試一些與Android AP不相關的類,或使用 Android的JUint 擴展來測試 Android 組件。如果你剛開始接觸 Android 測試,可以先從 AndroidTestCase開始寫一些通用目的的測試用例,然后再寫較復雜的測試用例。

  • Android JUint擴展提供了對 Android 特定組件的測試類,提供了創建mock對象輔助方法及控制組件生命周期的方法。

  • Test suite包含在測試包中,操作和主程序包類似。

  • Eclipse ADT包含了創建和測試的SDK 工具,并可通過命令行在其它IDE使用。這些工具從被測試的應用讀取信息并自動創建測試包的build 文件,mainfest文件和文件目錄結構。

  • SDK 提供了moneyrunner(用python書寫腳本)及Monkey(發送偽隨機事件的UI壓力測試工具)。


本文檔描述了android測試框架的基礎,包含測試結構、開發測試的API以及啟動測試和查看測試結果的工具。本文假設你有android應用編程以及JUnit測試的基礎。

測試框架圖如下:

測試結構

android的構建和測試工具假設測試項目都組織成類似測試、測試類、測試包和測試項目的標準結構。

android測試基于JUnit。通常JUnit測試就是測試“待測試應用”的方法。測試方法構成的類為test cases (或者test suites)。

JUnit 中編譯測試源文件到class文件中。類似地android中用android的編譯工具編譯測試包中的測試源文件為class文件。在JUnit 中test runner來執行測試類。在android中使用測試工具加載測試包和被測應用,然后調用android的test runner。

 

測試項目

測試項目就是一個目錄或者eclipse 工程,可在其中新建源代碼、manifest文件以及測試包的其它文件。建議使用Android tool創建測試項目:

  • 自動配置InstrumentationTestRunner為測試執行器。必須使用InstrumentationTestRunner或者其子類來執行JUnit測試。

  • 為測試包取合適的名字。如果被測應用為com.mydomain.myapp,Android tool自動命名測試包名為com.mydomain.myapp.test。

  • 自動創建合適的構建文件、manifest 文件以及目錄結構。


推薦的目錄結構:


  MyProject/
      AndroidManifest.xml
      res/
          ... (resources for main application)
      src/
          ... (source code for main application) ...
      tests/
          AndroidManifest.xml
          res/
              ... (resources for tests)
          src/
              ... (source code for tests)

注:這個在實際操作中往往根據IDE而不同,請以具體IDE的實例為準。 


測試API

Android測試API基于JUnit API 并擴展了instrumentation框架和Android特有的測試類。

JUnit


使用JUnit的TestCase類可對未使用android API的類進行單元測試。TestCase也是AndroidTestCase(測試依賴于android的對象)的基類。 AndroidTestCase還提供了android特有的 setup、teardown以及其它幫助方法。

JUnit的Assert類可以顯示結果,assert方法比較期望值與實際結果,在比較失敗時拋出異常。android同樣提供了擴展了比較類型的斷言類,以及用來測試UI的斷言類。

注意android測試API支持JUnit 3的代碼風格,不支持JUnit 4。

Instrumentation

android instrumentation是android系統中一系列控制方法或鉤子(hooks)。這些鉤子可以的正常生命周期內獨立地控制組件。它同樣可以控制android如何加載應用。

通常android組件會按照系統指定的生命周期來運行,例如Activity的生命周期開始于它被Intent激活,其onCreate()方法會被調 用,接下來是onResume(),當用戶啟動另外一個應用,onPause()方法會調用 ,如果Activity調用finish()方法,它的onDestroy()方法也會被調用。android framework API不會提供方法讓你在代碼中直接調用這些回調方法,但是用instrumentation可以。

系統把應用中的所有組件運行在同一個進程中,你可以讓一些組件,比如content provider,運行在單獨的進程中。但是無法強制應用與另外其他正在運行的應用運行在同一個進程中。

通過android imstrumentation,你可以在測試代碼中直接調用回調方法,讓你滲透組件的生命周期,就像調試。下面的測試代碼演示了如何用instrumentation來測試Activity保存和恢復狀態:
  

    // Start the main activity of the application under test
    mActivity = getActivity();
    
    // Get a handle to the Activity object's main UI widget, a Spinner
    mSpinner = (Spinner)mActivity.findViewById(com.android.example.spinner.R.id.Spinner01);
    
    // Set the Spinner to a known position
    mActivity.setSpinnerPosition(TEST_STATE_DESTROY_POSITION);
    
    // Stop the activity - The onDestroy() method should save the state of the Spinner
    mActivity.finish();
    
    // Re-start the Activity - the onResume() method should restore the state of the Spinner
    mActivity = getActivity();
    
    // Get the Spinner's current position
    int currentPosition = mActivity.getSpinnerPosition();
    
    // Assert that the current position is the same as the starting position
    assertEquals(TEST_STATE_DESTROY_POSITION, currentPosition);

代碼中使用的關鍵方法是getActivity(),它屬于android instrumentation API。調用該方法才會啟動Activity。你可以提前配置測試所需的環境(test fixture)。

Instrumentation可以加載測試包和被測試應用到同一個進程,這樣測試代碼可以調用應用組件的方法,修改和檢查組件中的域。

Test case 類


android提供了幾個繼承自TestCase和Assert的test case 類,它們都有andorid 特有的setup、teardown以及其它的輔助方法。


AndroidTestCase


通用的test case類,繼承了TestCase和Assert類。它提供了標準的JUnit中的setup()和teardown()方法,同時還有JUnit的Assert方法。另外它也提供了用來測試權限的方法以及通過清除一定的類引用來防止內存泄露的方法。

組件特有的test case

android測試框架的一個重要特點是組件test case類。它們有獨特的setup和teardown及控制組件生命周期。同時它們也提供mock方法。

1、Activity Testing

2、Content Provider Testing

3、Service Testing

Android并沒有為 BroadcastReceiver提供單獨的test case 類。可以通過測試發送Intent對象給它的組件來測試BroadcastReceiver,檢查BroadcastReceiver回復是否正確。

ApplicationTestCase


用 ApplicationTestCase測試Application對象的setup和teardown。這些對象維護著應用程序包中所有組件信息的全局 狀態,該test case 用于驗證manifest 文件中的<application>元素是否正確配置。然而記住這個test case無法控制應用包組件的測試。

InstrumentationTestCase

如果想在test case 類中使用 instrumentation 的方法,必須使用InstrumentationTestCase或者它的子類。Activity test case 繼承該基類。

Assertion 類

Android test case 類繼承自JUnit,可以用斷言來顯示測試結果。assertion方法將測試返回的真實值和期望值進行比較,如果比較失敗它會拋出AssertionException。用Assertion比打印log更方便,有更好的測試性能。

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

  • MoreAsserts包含更多強大的斷言,例如進行正則表達式匹配的assertContainsRegex(String, String)。

  • ViewAsserts包含很多關于View的斷言,例如它包含用來測試View是否在屏幕的特定的(x, y)位置的assertHasScreenCoordinates(View, View, int, int)方法,這些斷言簡化了UI中的幾何和對準測試。

模擬對象類


為了解決測試過程中的依賴,Android提供了創建模擬系統對象的類,比如Context對象、 ContentProvider對象、ContentResolver對象以及Service對象。有些test case能模擬的Intent對象。通過使用這些模擬對象,你可以將測試與系統的其余部分隔離開,同時也滿足了測試中的依賴,這些類都在包 android.test和android.test.mock中。

模擬對象通過打樁或者重載正常操作來實現將測試與正在運行的系統隔 離。例如MockContentResolver對象用它自有的與系統隔離的本地框架來代替通常的resolver框架。同時 MockContentResolver不使用notifyChange(Uri, ContentObserver, boolean)方法,這樣測試環境以外的observer對象不會被意外觸發。

模擬對象類也通過提供正常類的子類來滿足測試的依賴,該子類除了你覆寫的方法外其它都是不起作用的。例如,MockResources對象是Resources類的子類,每個方法在調用時都會拋出異常。要使用它,你只需要重載需要的方法。

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

基本的模擬對象類

MockApplication、 MockContext、MockContentProvider、MockCursor,、MockDialogInterface、 MockPackageManager和MockResources提供了簡單有用的模擬策略(打樁),在調用時都會拋出 UnsupportedOperationException異常。使用它,你只需要重載需要的方法。

注意:MockContentProvider和MockCursor是API Level 8 中新加入。

Resolver 模擬對象

MockContentResolver 通過屏蔽系統正常的resolver框架來為content provider 提供隔離的測試。MockContentResolver不是在系統中查找提供authority的content provider,而是使用自己的內部表,你必須顯式地用addProvider(String, ContentProvider)方法將provider添加到表中。

通過這個特性可以將模擬的content provider與authority關聯,新建provider對象但使用測試數據,你甚至可以設置provider的authority為null。 實際上MockContentResolver對象將你的測試與包含真實數據的provider隔離。你可以控制provider的功能并防止測試影響真 實數據。


Context測試


android提供了兩個Context類來提供測試:

  • IsolatedContext類提供隔離的Context,使用該Context的文件、目錄和數據庫操作都會在測試區域。盡管功能有限,但足以應對系統調用,允許在不影響當前設備上的真實數據的前提下測試應用的數據操作。

  • RenamingDelegatingContext 的Context的大部分功能都由現有的Context來處理,但是文件和數據庫操作都由IsolatedContext來處理,隔離的部分使用一個測試 目錄,并且創建特殊的文件和目錄名,你可以自己控制命名,也可以讓constructor自動指定。該類為進行數據操作創建隔離區域提供了快捷辦法,同時 不會影響Context其它的正常操作。

運行測試

test case由test runner類運行,test runner加載test case類、初始化、運行及清理測試。android test runner必須配置,這樣啟動應用的系統工具可以控制測試包如何加載test case和被測試應用。一般在manifest文件中設定。

InstrumentationTestRunner是android中主要的test runner類,它擴展了JUnit test runner框架并且是已配置,能夠執行任何android系統提供的test case 類并且支持所有類型的測試。

你 可指定測試包的manifest文件的<instrumentation>標簽內容為Instrumentation 或其子類。InstrumentationTestRunner的代碼在共享庫android.test.runner中,所以它通常沒有鏈接到你的代 碼,必須在<uses-library>標簽中指定。通常不需要手動去設定,Eclipse ADT以及android 命令行工具都會自動生成它們并且把它們加到測試包的manifest文件中。

注意:如果使用的是InstrumentationTestRunner之外的test runner,必須修改<instrumentation>標簽并指向你想使用的類。

要運行InstrumentationTestRunner類必須用android 工具調用內部系統類。Eclipse ADT中這些類都會被自動調用,命令行工具執行測試的時用Android Debug Bridge (adb)運行這些類。

系 統類加載和啟動測試包,殺掉被測試應用包正在運行的進程,并且重新加載被測試包的實體,然后它們把控制權交給 InstrumentationTestRunner,由它來執行測試包中的每個test case。你也可以通過Eclipse ADT中的setting或者命令行工具中的flag來控制哪些 test case或者方法的運行。

既不是系統類也不是 InstrumentationTestRunner運行被測試應用,而是test case。它要么調用被測試包中的方法,要么調用它自己的方法以改變被測試包生命周期。應用程序完全由test case 控制,測試開始前由test case來初始化測試環境,

關于更多的運行測試,可以參見 Testing from Eclipse with ADT Testing from Other IDEs

查看測試結果

Android 測試框架返回測試結果給啟動測試的工具。在eclipse ADT中結果會在新的JUnit視圖面板中顯示,命令行會在STDOUT中顯示。兩者都可以看到顯示每個test case 名字和你所運行的方法的小結,同時會看到所有失敗的斷言,其中包含指向產生失敗的測試代碼所在行的鏈接。失敗的斷言同時也會列出期望值和實際值。

測試結果根據IDE不同而有不同。


monkey 和 monkeyrunner


SDK提供了兩個應用測試工具:

  • UI/Application Exerciser Monkey,通常稱為"monkey",向設備發送偽隨機事件流(如擊鍵、觸控、手勢)的命令行工具。你可以通過Android Debug Bridge (adb)來運行它,對應用進行壓力測試然后報告遇到的錯誤。你可以通過每次使用相同的隨機數種子來重復步驟。

  • monkeyrunner是一套API,基于Python。該API包含如下功能:連接到設備、安裝和卸載軟件包、截圖、比較圖片、運行應用對應的測試應用。通過該API,你可以寫出功能強大復雜的測試,通過命令行工具monkeyrunner來運行。

 

處理包名

 

測試環境需要同時處理android應用包名和java包標識符。它們都使用同樣的命名格式,但是代表著完全不同的實體。

android 包名是.apk文件對應的一個獨一無二的系統名字,由應用包的manifest文件中<manifest>標簽中 的"android:package"屬性來設定。測試包的名字必須和被測試包的名字不同,通常android工具會用被測試包的名字后加 上".test"來作為測試包的名字。

測試包也會用包名來定位它所測試的應用,元由測試包的manifest文件中<instrumentation>素的"android:targetPackage"屬性設定。


java包標識符對應源文件,包名反映了源文件所在目錄,它同時會影響類與成員間彼此的可訪問性。

android 工具會幫助你設定測試包的名字。根據你的輸入,工具會設定測試包的名字以及測試的目標包的名字。只有在被測試應用工程已經存在的情況下這些工具才會起作用。

默 認情況下,這些工具會將測試類的包標識符設定為與被測試應用的包標示符一致。如果你想暴露被測試包中的一些成員你可能需要做一些修改。如果要修改,只修改 java 包標示符,不要修改android 包名,只修改test case 的源文件而不要修改測試包中R.java文件的包名,因為修改它會造成與被測試包中的R.java類沖突。不要將測試包的android包名修改成和它所 測試的應用的包名一樣,因為這樣它們的名字在系統中不再是獨一無二的。

測試內容

What To Test詳細地描述了android應用中應該被測試的關鍵功能以及可能會影響該功能的狀況。

大部分的單元測試是專門針對你正在測試的andorid組件。Activity Testing、 Content Provider Testing和 Service Testing中都有一章節列出“需要測試什么”。

盡量在真實的設備上運行這些測試。其次用Android Emulator來加載已經配置好你所希望測試的硬件、屏幕、版本的android vitual device。

 

參考資料

http://developer.android.com/intl/zh-cn/tools/testing/testing_android.html

http://www.uml.org.cn/mobiledev/201306074.asp

本文地址:http://www.cnblogs.com/pythontesting/p/4916574.html



來自: http://my.oschina.net/u/1433482/blog/602003

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!