溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

android基礎(chǔ)知識12:android自動化測試06—Instrumentation 02 單元測試

發(fā)布時間:2020-10-14 12:53:30 來源:網(wǎng)絡(luò) 閱讀:330 作者:zhukev 欄目:移動開發(fā)

轉(zhuǎn)載處(原文出處不可靠,否則請指正):http://blog.csdn.net/xianming01/article/details/7893402

【IT168 技術(shù)文檔】任何程序的開發(fā)都離不開單元測試來保證其健壯和穩(wěn)定。Android的程序自然也不例外。從Android SDK 0.9開始,就有了比較成熟的測試框架,但是直到目前最新的1.1版本,也沒有詳細(xì)的文檔介紹這個內(nèi)容,只是簡單的給了一個Api Demos里的幾個單元測試代碼。因此,我在這里對此內(nèi)容做一下梳理和總結(jié):


  JUnit還能用么?

  在 Java下做單元測試必然用到JUnit。這里說的JUnit是指從Apache基金會下載的junit.jar里提供的一系列單元測試功能。這些功能顯然是運(yùn)行在JDK之上的。在Android下已經(jīng)沒有了JDK,自然也無法運(yùn)行JUnit。但是這并不妨礙我們利用JUnit編寫單元測試。只不過在運(yùn)行單元測試時,一定要用JDK來運(yùn)行,利用java命令來啟動JUnit的某個Runner。如果是用Eclipse的話,可以在Run Configuration里新建一個JUnit。但是一定要記得在Classpath選項卡里將Bootstrap Entries中的Android Library改成JRE,并且添加junit.jar。

android基礎(chǔ)知識12:android自動化測試06—Instrumentation 02 單元測試

很明顯的,這種測試就是正規(guī)的Java單元測試,和Android沒有任何關(guān)系。你無法測試任何關(guān)于Android系統(tǒng)中的API,你寫的Activity,人機(jī)界面等等。所以,如果你想測試僅僅是一些封裝數(shù)據(jù)的對象,或者是純粹的數(shù)值計算,還是可以用這種方法的。

  Android里面的junit.framework包是怎么回事?

  很多人看到這個包的時候,第一反應(yīng)是Android是不是已經(jīng)完整集成了JUnit。很遺憾這不是事實。如果你按照JUnit的運(yùn)行方法,卻不像上面那樣改用JDK,就一定會得到一個異常:

  #

  # An unexpected error hasbeen detected by Java Runtime Environment:

  #

  # Internal Error(classFileParser.cpp:2924), pid=4900, tid=4476

  #Error:ShouldNotReachHere()

  #

  # Java VM: JavaHotSpot(TM) Client VM (10.0-b19 mixed mode windows-x86)

  # An error report filewith more information is saved as:

  #E:\Mydoc\EclipseWorkspace\TestAndroid\hs_err_pid4900.log

  #

  # If you would like tosubmit a bug report, please visit:

  #http://java.sun.com/webapps/bugreport/crash.jsp

  #

  實際上,TestCase這個類用于在Android擔(dān)當(dāng)所有獨(dú)特的TestCase的基類的作用,它是一個Abstract ClassAndroid單元測試類繼承關(guān)系圖如下所示:

android基礎(chǔ)知識12:android自動化測試06—Instrumentation 02 單元測試

之所以有那么多XXXTestCase主要是為了簡化工作。例如當(dāng)你想對一個訪問數(shù)據(jù)庫的功能進(jìn)行測試時,首先需要自己啟動并初始化數(shù)據(jù)庫。在這里是類似的,如果你想測試一個Activity,首先要啟動它。而ActivityTestCase就會自動幫你做完這些事情。而 ActivityUnitTestCase會更注重測試的獨(dú)立性,它會讓測試與Android底層的聯(lián)系降到最低。其余的類可以查看相關(guān)的Javadoc 來按需挑選。要編寫測試,就是找到合適的XXXTestCase作為基類來繼承,并且編寫自己的測試方法。
  很明顯的,最簡單的編寫測試的方法就是繼承AndroidTestCase寫一個自己的TestCase。然后為自己的一組TestCase寫一個Activity界面,由界面控制 TestCase的啟動,運(yùn)行和結(jié)果報告。但是,你很快會發(fā)現(xiàn),為何要給測試寫一個界面呢?這太詭異了。這時就需要一種技術(shù),它可以利用命令行(Shell)來啟動一組測試,并且通過命令行的形式給出結(jié)果。這就是所謂的Instrumentation。


什么是Instrumentation?


  一般在開發(fā)Android程序的時候,需要寫一個manifest文件,其結(jié)構(gòu)是:

[html] view plaincopy
  1. <application android:icon="@drawable/icon" android:label="@string/app_name">  
  2. <activity android:name=".TestApp" android:label="@string/app_name">  
  3. ……  
  4. </activity>  
  5. </application>   

         這樣,在啟動程序的時候就會先啟動一個Application,然后在此Application運(yùn)行過程中根據(jù)情況加載相應(yīng)的Activity,而Activity是需要一個界面的。但是Instrumentation并不是這樣的。你可以將Instrumentation理解為一種沒有圖形界面的,具有啟動能力的,用于監(jiān)控其他類(用Target Package聲明)的工具類。任何想成為Instrumentation的類必須繼承android.app.Instrumentation。下面是這個類的解釋:

  “Base class for implementingapplication instrumentation code. When running with instrumentation turned on,this class will be instantiated for you before any of the application code,allowing you to monitor all of the interaction the system has with the application.An Instrumentation implementation is described to the system through anAndroidManifest.xml's tag.“

  對于單元測試,我們需要認(rèn)真了解的就是android.test.InstrumentationTestRunner類。這是Android單元測試的主入口。它相當(dāng)于JUnit當(dāng)中TestRunner的作用。

  那么如何加載它呢,首先要在manifest文件中加入一行關(guān)于Instrumentation的聲明。比如Android Api Demos中的測試?yán)锏膍anifest是這么寫的(我濾掉了所有的注釋):

[html] view plaincopy
  1. <manifest xmlns:android="http://schemas.android.com/apk/res/android"  
  2. package="com.example.android.apis.tests">  
  3.     <application>  
  4.        <uses-library android:name="android.test.runner" />  
  5.   
  6.     </application>  
  7.   
  8.     <instrumentation android:name="android.test.InstrumentationTestRunner"  
  9.   
  10.       android:targetPackage="com.example.android.apis"  
  11.   
  12.         android:label="Tests for Api Demos."/>  
  13.   
  14. </manifest>   
如果用Eclipse的ADT插件(0.8版本以上),也可以用圖形界面來添加,如下圖:

android基礎(chǔ)知識12:android自動化測試06—Instrumentation 02 單元測試

  編輯好 manifest,就可以打包(build,可以用Eclipse ADT來做,也可以用aapt命令手工完成),然后安裝到虛擬機(jī)上(用adb install命令)。之后就可以利用命令行的方式來加載你的單元測試了。在Android Shell中加載一個Instrumentation的方法是利用以下命令:

  adb shell am instrument –w XXXXXX

  其中-w是指定Instrumentation類的參數(shù)標(biāo)志。一個簡單的例子是:

  adb shell am instrument -wcom.android.foo/android.test.InstrumentationTestRunner

  當(dāng)然,也可以利用adb shell先進(jìn)入android命令行模式,再直接寫am instrument –w XXXXXXX。下面將具體介紹如何將根據(jù)需要加載一組單元測試。

如何在Android中利用Instrumentation來進(jìn)行測試?

  在介紹具體的命令之前,我們先理解一下單元測試的層次。一組單元測試可以被組織成若干個TestSuite。每個TestSuite包含若干 TestCase(某個繼承android.jar的junit.framework.TestCase的類)。每個TestCase又包含若干個 Test(具體的test方法)。

  如果假設(shè)com.android.foo是你的測試代碼的包的根。當(dāng)執(zhí)行以下命令時,會執(zhí)行所有的TestCase的所有Test。測試的對象就是在Target Package中指定的包中的代碼:

  adb shell am instrument -wcom.android.foo/android.test.InstrumentationTestRunner

  如果你想運(yùn)行一個TestSuite,首先繼承android.jar的junit.framework.TestSuite類,實現(xiàn)一個 TestSuite(比如叫com.android.foo.MyTestSuite),然后執(zhí)行以下命令執(zhí)行此TestSuite

  adb shell am instrument -e classcom.android.foo.MyTestSuite -wcom.android.foo/android.test.InstrumentationTestRunner

  其中的-e表示額外的參數(shù),語法為-e [arg1] [value1] [arg2] [value2]…這里用到了class參數(shù)。

  如果僅僅想運(yùn)行一個TestCase(比如叫com.android.foo.MyTestCase),則用以下命令:

  adb shell am instrument -e classcom.android.foo.MyTestCase -wcom.android.foo/android.test.InstrumentationTestRunner

  如果僅僅想運(yùn)行一個Test(比如就是上面MyTestCase的testFoo方法),很類似的,就這樣寫:

  adb shell am instrument -e classcom.android.foo.MyTestCase#testFoo -wcom.android.foo/android.test.InstrumentationTestRunner

  然后,所有的測試結(jié)果會輸出到控制臺,并會做一系列統(tǒng)計,如標(biāo)記為E的是Error,標(biāo)記為F的是Failure,Success的測試則會標(biāo)記為一個點。這和JUnit的語義一致。如果希望斷點調(diào)試你的測試,只需要直接在代碼上加上斷點,然后將運(yùn)行命令參數(shù)的-e后邊附加上debug true后運(yùn)行即可。更加詳細(xì)的內(nèi)容可以看InstrumentationTestRunner的Javadoc。我希望Android能盡快有正式的文檔來介紹這個內(nèi)容。

  如何在Android的單元測試中做標(biāo)記?

  在 android.test.annotation包里定義了幾個annotation,包括 @LargeTest,@MediumTest,@SmallTest,@Smoke,和@Suppress。你可以根據(jù)自己的需要用這些 annotation來對自己的測試分類。在執(zhí)行單元測試命令時,可以在-e參數(shù)后設(shè)置“size large”/ “size medium”/ “size small”來執(zhí)行具有相應(yīng)標(biāo)記的測試。特別的@Supperss可以取消被標(biāo)記的Test的執(zhí)行。

  完整的操作過程

  總結(jié)以上所有的內(nèi)容,編寫并運(yùn)行完整的測試需要以下的步驟:

android基礎(chǔ)知識12:android自動化測試06—Instrumentation 02 單元測試

  以上步驟中,在 Android自帶的例子中,我發(fā)現(xiàn)它有兩個manifest.xml。也就是說在步驟3中源代碼和測試代碼分別生成了兩個不同的包。然后步驟4利用 adb install命令安裝到了虛擬機(jī)上。由于我沒有找到Eclipse ADT有辦法可以為一個只有Instrumentation,沒有Activity的Application打包并安裝,于是采用了略微不同的辦法完成了這個工作。下文中將一一詳細(xì)介紹整個過程。

1、編寫程序

  我新建了一個項目TestApp,參數(shù)為:

  Package Name: com.android.testapp

  Activity Name: MainActivity

  Application Name: TestApp

  以下是MainActivity的源代碼:

[java] view plaincopy
  1. packagecom.android.testapp;  
  2.   importandroid.app.Activity;  
  3.   importandroid.os.Bundle;  
  4.   publicclassMainActivityextendsActivity {  
  5.   /** Called when the activity is first created. */  
  6.   @Override  
  7.   publicvoidonCreate(Bundle savedInstanceState) {  
  8.   super.onCreate(savedInstanceState);  
  9.   setContentView(R.layout.main);  
  10.   }  
  11.   publicintsum(inta,intb) {  
  12.   returna + b;  
  13.   }  
  14.   publicintsubstract(inta,intb) {  
  15.   returnb - a;  
  16.   }  
  17.   }  

其中,我故意將減法的a – b寫成了b – a。

2、編寫測試程序

  然后,我新建了一個Source Folder,名為test,并在里面新建了包com.android.testapp.test。并定義了一個TestCase,名為TestMainActivity,源代碼如下:

[java] view plaincopy
  1. package com.android.testapp.test;  
  2.   import com.android.testapp.MainActivity;  
  3.   import android.test.ActivityInstrumentationTestCase;  
  4.   import android.test.suitebuilder.annotation.MediumTest;  
  5.   public class TestMainActivity extends ActivityInstrumentationTestCase {  
  6.   public TestMainActivity() {  
  7.   super("com.android.testapp", MainActivity.class);  
  8.   }  
  9.   public TestMainActivity(String pkg, Class activityClass) {  
  10.   super(pkg, activityClass);  
  11.   }  
  12.   @MediumTest  
  13.   public void testSum() {  
  14.   assertEquals(3, getActivity().sum(12));  
  15.   }  
  16.   @MediumTest  
  17.   public void testSubstract() {  
  18.   assertEquals(-1, getActivity().substract(12));  
  19.   }  
  20.   }  

我繼承了ActivityInstrumentationTestCase。這個TestCase在執(zhí)行時會自動幫我啟動相應(yīng)的Activity。

  接下來就是程序的Manifest:

[html] view plaincopy
  1. <?xml version="1.0" encoding="utf-8"?>   
  2.   
  3. <manifest xmlns:android="http://schemas.android.com/apk/res/android"   
  4.   
  5. package="com.android.testapp"   
  6.   
  7. android:versionCode="1"   
  8.   
  9. android:versionName="1.0.0">   
  10.   
  11. <application android:icon="@drawable/icon" android:label="@string/app_name">   
  12.   
  13. <activity android:name=".MainActivity"   
  14.   
  15. android:label="@string/app_name">   
  16.   
  17. <intent-filter>   
  18.   
  19. <action android:name="android.intent.action.MAIN" />   
  20.   
  21. <category android:name="android.intent.category.LAUNCHER" />   
  22.   
  23. </intent-filter>   
  24.   
  25. </activity>   
  26.   
  27. <uses-library android:name="android.test.runner" />   
  28.   
  29. </application>   
  30.   
  31. <instrumentation android:targetPackage="com.android.testapp" android:name="android.test.InstrumentationTestRunner" android:label="Test Unit Tests"></instrumentation>   
  32.   
  33. </manifest>   

在這個文件中,我將 Activity和Instrumentation的聲明寫到了一起,而沒有像Apis Demo那樣分開。請注意里面的標(biāo)簽。如果沒有那句,在運(yùn)行測試時會報告找不到TestRunner。這是由于 Android在build的時候只把需要的東西打包,所以你必須明確的告訴Android Builder這一點。

3、Build和Install

  在 Eclipse上,這兩個步驟是一起完成的。只要點一下Run即可。只不過如果你不在Run Configuration里將安裝后的Launch Action設(shè)為“Do Nothing”,就會自動運(yùn)行一下你的MainActivity。對于我們,設(shè)為Do Nothing即可。如下圖:

android基礎(chǔ)知識12:android自動化測試06—Instrumentation 02 單元測試

完成后,利用命令:

  adb shell pm list packages

  可以在已經(jīng)安裝的pkg列表里看到com.android.testapp。

  4、運(yùn)行測試,查看結(jié)果

  之后就打開命令行,運(yùn)行以下命令

  adb shell am instrument –e classcom.android.testapp.test.TestMainActivity –wcom.android.testapp/android.test.InstrumentationTestRunner

  即可看到如下的結(jié)果:

android基礎(chǔ)知識12:android自動化測試06—Instrumentation 02 單元測試

  可以看到,單元測試正確的找到了減法中的錯誤。結(jié)果中的成功的測試顯示為”.”,一個失敗的顯示為”F”。只不過我還是不太理解為什么我只寫了兩個測試方法,Tests run卻顯示了3。


參考資料:

《android上的單元測試》


向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI