[android]android自動化測試十之單元測試例項

大搜車-自娛發表於2012-04-05
android原始碼中每個app下中都自帶了一個test用例,下面主要介紹下camra單元測試用例

在AndroidManifest.xml中標明瞭測試用例instrumentation函式入口

Java程式碼
<?xml version="1.0" encoding="utf-8"?>  
<!-- Copyright (C) 2008 The Android Open Source Project

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.camera.tests">

<application>
<uses-library android:name="android.test.runner" />
</application>

<instrumentation android:name="CameraLaunchPerformance"
android:targetPackage="com.android.camera"
android:label="Camera Launch Performance">
</instrumentation>

<instrumentation android:name="com.android.camera.CameraStressTestRunner"
android:targetPackage="com.android.camera"
android:label="Camera Stress Test InstrumentationRunner">
</instrumentation>

<instrumentation android:name="android.test.InstrumentationTestRunner"
android:targetPackage="com.android.camera"
android:label="Tests for Camera application."/>
</manifest>



camera啟動效能測試
Java程式碼
package com.android.camera;  

import android.app.Activity;
import android.os.Bundle;
import android.test.LaunchPerformanceBase;

/**
* Instrumentation class for Camera launch performance testing.
*/
public class CameraLaunchPerformance extends LaunchPerformanceBase {

public static final String LOG_TAG = "CameraLaunchPerformance";

public CameraLaunchPerformance() {
super();
}

@Override
public void onCreate(Bundle arguments) {
super.onCreate(arguments);

mIntent.setClassName(getTargetContext(), "com.android.camera.Camera");
start();
}

/**
* Calls LaunchApp and finish.
*/
@Override
public void onStart() {
super.onStart();
LaunchApp();
finish(Activity.RESULT_OK, mResults);
}
}


camera拍照壓力測試,引數設定為反覆拍照100次

Java程式碼
package com.android.camera.stress;  

import com.android.camera.Camera;

import android.app.Instrumentation;
import android.test.ActivityInstrumentationTestCase2;
import android.test.suitebuilder.annotation.LargeTest;
import android.util.Log;
import android.view.KeyEvent;

/**
* Junit / Instrumentation test case for camera test
*
* Running the test suite:
*
* adb shell am instrument \
* -e class com.android.camera.stress.ImageCapture \
* -w com.android.camera.tests/com.android.camera.CameraStressTestRunner
*
*/

public class ImageCapture extends ActivityInstrumentationTestCase2 <Camera> {
private String TAG = "ImageCapture";
private static final int TOTAL_NUMBER_OF_IMAGECAPTURE = 100;
private static final int TOTAL_NUMBER_OF_VIDEOCAPTURE = 100;
private static final long WAIT_FOR_IMAGE_CAPTURE_TO_BE_TAKEN = 1000;
private static final long WAIT_FOR_VIDEO_CAPTURE_TO_BE_TAKEN = 50000; //50seconds
private static final long WAIT_FOR_PREVIEW = 1000; //1 seconds

public ImageCapture() {
super("com.android.camera", Camera.class);
}

@Override
protected void setUp() throws Exception {
getActivity();
super.setUp();
}

@Override
protected void tearDown() throws Exception {
super.tearDown();
}

@LargeTest
public void testImageCapture() {
Instrumentation inst = getInstrumentation();
try {
for (int i = 0; i < TOTAL_NUMBER_OF_IMAGECAPTURE; i++) {
Thread.sleep(WAIT_FOR_IMAGE_CAPTURE_TO_BE_TAKEN);
inst.sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_UP);
inst.sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_CENTER);
Thread.sleep(WAIT_FOR_IMAGE_CAPTURE_TO_BE_TAKEN);
}
} catch (Exception e) {
Log.v(TAG, e.toString());
}
assertTrue("testImageCapture", true);
}

@LargeTest
public void testVideoCapture() {
Instrumentation inst = getInstrumentation();
//Switch to the video mode
inst.sendKeyDownUpSync(KeyEvent.KEYCODE_MENU);
inst.sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_CENTER);
try {
for (int i = 0; i < TOTAL_NUMBER_OF_VIDEOCAPTURE; i++) {
Thread.sleep(WAIT_FOR_PREVIEW);
inst.sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_UP);
//record an video
inst.sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_CENTER);
Thread.sleep(WAIT_FOR_VIDEO_CAPTURE_TO_BE_TAKEN);
inst.sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_CENTER);
Thread.sleep(WAIT_FOR_PREVIEW);
inst.sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_CENTER);
}
} catch (Exception e) {
Log.v(TAG, e.toString());
}
assertTrue("testVideoCapture", true);
}

}



camera拍照視訊錄製切換測試

Java程式碼
package com.android.camera.stress;  

import com.android.camera.VideoCamera;

import android.app.Instrumentation;
import android.test.ActivityInstrumentationTestCase2;
import android.test.suitebuilder.annotation.LargeTest;
import android.util.Log;
import android.view.KeyEvent;

/**
* Junit / Instrumentation test case for camera test
*
* Running the test suite:
*
* adb shell am instrument \
* -e class com.android.camera.stress.SwitchPreview \
* -w com.android.camera.tests/com.android.camera.CameraStressTestRunner
*
*/
public class SwitchPreview extends ActivityInstrumentationTestCase2 <VideoCamera>{
private String TAG = "SwitchPreview";
private static final int TOTAL_NUMBER_OF_SWITCHING = 200;
private static final long WAIT_FOR_PREVIEW = 2000;


public SwitchPreview() {
super("com.android.camera", VideoCamera.class);
}

@Override
protected void setUp() throws Exception {
getActivity();
super.setUp();
}

@Override
protected void tearDown() throws Exception {
getActivity().finish();
super.tearDown();
}

@LargeTest
public void testSwitchMode() {
//Switching the video and the video recorder mode
Instrumentation inst = getInstrumentation();
try{
for (int i=0; i< TOTAL_NUMBER_OF_SWITCHING; i++) {
Thread.sleep(WAIT_FOR_PREVIEW);
inst.sendKeyDownUpSync(KeyEvent.KEYCODE_MENU);
inst.sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_LEFT);
inst.sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_CENTER);
Thread.sleep(WAIT_FOR_PREVIEW);
}
} catch (Exception e){
Log.v(TAG, e.toString());
}
assertTrue("testSwitchMode",true);
}
}




如果想在android裡面做單元測試,有兩條基本的路子可行。

  第一, 就是java程式設計師最為熟悉和常用的JUnit, 但是由於目前android sdk (version 1.1)中只是提供了stubbed methods/classes,沒有具體的實現程式碼,所以如果用JUnit的話,我們需要在執行單元測試時,一定要用JDK來執行,利用java命令來啟動JUnit的某個Runner。如果是用Eclipse的話,可以在Run Configuration裡新建一個JUnit。但是一定要記得在Classpath選項卡里將Bootstrap Entries中的Android Library改成JRE,並且新增junit.jar。具體的設定可以參考:http://developer.android.com/guide /appendix/faq/troubleshooting.html#addjunit。而且,更為遺憾的是,這種方法執行的JUnit執行在JDK之上的,而不是android,所以,只能測試一些和android無關的東西,比如業務邏輯,資料封裝,數值計算等等。並不能測試android api。

  第二, 採用Instrumentation. Android單元測試的主入口是InstrumentationTestRunner。它相當於JUnit當中TestRunner的作用。你可以將 Instrumentation理解為一種沒有圖形介面的,具有啟動能力的,用於監控其他類(用Target Package宣告)的工具類。任何想成為Instrumentation的類必須繼承android.app.Instrumentation。

  下面通過一個例項來看一下如何通過Instrumentation來做單元測試。

  Step 1.首先編寫需要測試的activity:

Java程式碼
import android.app.Activity;  
import android.os.Bundle;

public class AndroidUT extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}

public int add(int a, int b)
{
return a + b;
}
}



  Step 2.

  接下來編寫測試類,其中主要來測試add()方法。我們在當前程式碼目錄下,在新建一個資料夾,命名為test,並在裡面新建了包com.android.ut.test。然後往裡面新增加一個class.具體如下:

Java程式碼
import com.android.ut.AndroidUT;  

import android.test.ActivityInstrumentationTestCase;

public class TestApp extends ActivityInstrumentationTestCase<AndroidUT> {

public TestApp()
{
super("com.android.ut", AndroidUT.class);
}

public void testSum()
{
assertEquals(5, getActivity().add(2, 3));
}
}


  Step 3.最後一步就是要改一下Manifest檔案。

Java程式碼
<?xml version="1.0" encoding="utf-8"?>  
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.ut"
android:versionCode="1"
android:versionName="1.0.0">
<application android:icon="@drawable/icon" android:label="@string/app_name">
<activity android:name=".AndroidUT"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<uses-library android:name="android.test.runner" />
</application>
<instrumentation android:targetPackage="com.android.ut" android:name="android.test.InstrumentationTestRunner" android:label="Test Unit Tests"></instrumentation>
</manifest>

  需要注意的是,在這裡面我加上了:

  
Java程式碼
<uses-library android:name="android.test.runner" />  



  以及:

  
Java程式碼
<instrumentation android:targetPackage="com.android.ut" android:name="android.test.InstrumentationTestRunner" android:label="Test Unit Tests"></instrumentation>  

  Step 4.執行

  首先通過模擬器執行一下AndroidUT,然後在命令列終端中執行
Java程式碼
adb shell am instrument -e class com.android.ut.test.TestApp -wcom.android.ut/android.test.InstrumentationTestRunner  


  這樣你就可以看到測試結果了。

Java程式碼
# am instrument -e class com.cn.test.TestApp -w com.cn/android.test.InstrumentationTestRunner  


com.cn.test.TestApp:..
Test results for InstrumentationTestRunner=..
Time: 2.866

OK (2 tests)


後臺測試log日誌資訊

Java程式碼
D/AndroidRuntime(  941): >>>>>>>>>>>>>> AndroidRuntime START <<<<<<<<<<<<<<  
D/AndroidRuntime( 941): CheckJNI is ON
D/AndroidRuntime( 941): --- registering native functions ---
D/FileBackupHelper_native( 941): register_android_backup_FileBackupHelper
D/ActivityManager( 581): Uninstalling process com.cn
I/ActivityManager( 581): Start proc com.cn for added application com.cn: pid=948 uid=10013 gids={}
I/TestRunner( 948): started: testSum(com.cn.test.TestApp) //啟動add()測試方法
I/ActivityManager( 581): Starting activity: Intent { act=android.intent.action.MAIN flg=0x10000000 cmp=com.cn/.AndroidUT }
I/ActivityManager( 581): Displayed activity com.cn/.AndroidUT: 645 ms (total 645 ms)
I/TestRunner( 948): finished: testSum(com.cn.test.TestApp)
I/TestRunner( 948): passed: testSum(com.cn.test.TestApp)
I/TestRunner( 948): started: testActivityTestCaseSetUpProperly(com.cn.test.TestApp)
I/ActivityManager( 581): Starting activity: Intent { act=android.intent.action.MAIN flg=0x10000000 cmp=com.cn/.AndroidUT }
I/ActivityManager( 581): Displayed activity com.cn/.AndroidUT: 412 ms (total 412 ms)
I/TestRunner( 948): finished: testActivityTestCaseSetUpProperly(com.cn.test.TestApp)
I/TestRunner( 948): passed: testActivityTestCaseSetUpProperly(com.cn.test.TestApp)
D/ActivityManager( 581): Uninstalling process com.cn
D/ActivityManager( 581): Force removing process ProcessRecord{43851fa0 948:com.cn/10013} (com.cn/10013)
D/AndroidRuntime( 941): Shutting down VM



(二) 轉

任何程式的開發都離不開單元測試來保證其健壯和穩定。Android的程式自然也不例外。從Android SDK 0.9開始,就有了比較成熟的測試框架,但是直到目前最新的1.1版本,也沒有詳細的文件介紹這個內容,只是簡單的給了一個Api Demos裡的幾個單元測試程式碼。因此,我在這裡對此內容做一下梳理和總結: JUnit還能用麼?

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


很明顯的,這種測試就是正規的Java單元測試,和Android沒有任何關係。你無法測試任何關於Android系統中的API,你寫的Activity,人機介面等等。所以,如果你想測試僅僅是一些封裝資料的物件,或者是純粹的數值計算,還是可以用這種方法的。 Android裡面的junit.framework包是怎麼回事?

很多人看到這個包的時候,第一反應是Android是不是已經完整整合了JUnit。很遺憾這不是事實。如果你按照JUnit的執行方法,卻不像上面那樣改用JDK,就一定會得到一個異常:
Java程式碼
#  
# An unexpected error has been detected by Java Runtime Environment:
#
# Internal Error (classFileParser.cpp:2924), pid=4900, tid=4476
#Error: ShouldNotReachHere()
#
# Java VM: Java HotSpot(TM) Client VM (10.0-b19 mixed mode windows-x86)
# An error report file with more information is saved as:
# E:\Mydoc\EclipseWorkspace\TestAndroid\hs_err_pid4900.log
#
# If you would like to submit a bug report, please visit:
# http://java.sun.com/webapps/bugreport/crash.jsp
#


實際上,TestCase這個類用於在Android擔當所有獨特的TestCase的基類的作用,它是一個Abstract Class。Android單元測試類繼承關係圖如下所示:


之所以有那麼多XXXTestCase主要是為了簡化工作。例如當你想對一個訪問資料庫的功能進行測試時,首先需要自己啟動並初始化資料庫。在這裡是類似的,如果你想測試一個Activity,首先要啟動它。而ActivityTestCase就會自動幫你做完這些事情。而 ActivityUnitTestCase會更注重測試的獨立性,它會讓測試與Android底層的聯絡降到最低。其餘的類可以檢視相關的Javadoc 來按需挑選。要編寫測試,就是找到合適的XXXTestCase作為基類來繼承,並且編寫自己的測試方法。

很明顯的,最簡單的編寫測試的方法就是繼承AndroidTestCase寫一個自己的TestCase。然後為自己的一組 TestCase寫一個Activity介面,由介面控制TestCase的啟動,執行和結果報告。但是,你很快會發現,為何要給測試寫一個介面呢?這太詭異了。這時就需要一種技術,它可以利用命令列(Shell)來啟動一組測試,並且通過命令列的形式給出結果。這就是所謂的 Instrumentation。 什麼是Instrumentation?

一般在開發Android程式的時候,需要寫一個manifest檔案,其結構是:

Java程式碼
<application android:icon="@drawable/icon" android:label="@string/app_name">  

<activity android:name=".TestApp" android:label="@string/app_name">

……

</activity>

</application>


這樣,在啟動程式的時候就會先啟動一個Application,然後在此Application執行過程中根據情況載入相應的 Activity,而Activity是需要一個介面的。但是Instrumentation並不是這樣的。你可以將Instrumentation理解為一種沒有圖形介面的,具有啟動能力的,用於監控其他類(用Target Package宣告)的工具類。任何想成為Instrumentation的類必須繼承android.app.Instrumentation。下面是這個類的解釋:

Base class for implementing application 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 an AndroidManifest.xml's <instrumentation> tag.

對於單元測試,我們需要認真瞭解的就是android.test.InstrumentationTestRunner類。這是Android單元測試的主入口。它相當於JUnit當中TestRunner的作用。

那麼如何載入它呢,首先要在manifest檔案中加入一行關於Instrumentation的宣告。比如Android Api Demos中的測試裡的manifest是這麼寫的(我濾掉了所有的註釋):

Java程式碼
<manifest xmlns:android="http://schemas.android.com/apk/res/android"  

package="com.example.android.apis.tests">

<application>

<uses-library android:name="android.test.runner" />

</application>

<instrumentation android:name="android.test.InstrumentationTestRunner"

android:targetPackage="com.example.android.apis"

android:label="Tests for Api Demos."/>

</manifest>


如果用Eclipse的ADT外掛(0.8版本以上),也可以用圖形介面來新增,如下圖:


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

Java程式碼
adb shell am instrument –w XXXXXX


其中-w是指定Instrumentation類的引數標誌。一個簡單的例子是:

Java程式碼
adb shell am instrument -w com.android.foo/android.test.InstrumentationTestRunner  


當然,也可以利用adb shell先進入android命令列模式,再直接寫am instrument –w XXXXXXX。下面將具體介紹如何將根據需要載入一組單元測試。 如何在Android中利用Instrumentation來進行測試?

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

如果假設com.android.foo是你的測試程式碼的包的根。當執行以下命令時,會執行所有的TestCase的所有Test。測試的物件就是在Target Package中指定的包中的程式碼:

Java程式碼
adb shell am instrument -w com.android.foo/android.test.InstrumentationTestRunner

如果你想執行一個TestSuite,首先繼承android.jar的junit.framework.TestSuite類,實現一個TestSuite(比如叫com.android.foo.MyTestSuite),然後執行以下命令執行此TestSuite

Java程式碼
adb shell am instrument -e class com.android.foo.MyTestSuite -w com.android.foo/android.test.InstrumentationTestRunner  


其中的-e表示額外的引數,語法為-e [arg1] [value1] [arg2] [value2] …這裡用到了class引數。

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

Java程式碼
adb shell am instrument -e class com.android.foo.MyTestCase -w com.android.foo/android.test.InstrumentationTestRunner


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

Java程式碼
adb shell am instrument -e class com.android.foo.MyTestCase#testFoo -w com.android.foo/android.test.InstrumentationTestRunner  

然後,所有的測試結果會輸出到控制檯,並會做一系列統計,如標記為E的是Error,標記為F的是Failure,Success的測試則會標記為一個點。這和JUnit的語義一致。如果希望斷點除錯你的測試,只需要直接在程式碼上加上斷點,然後將執行命令引數的-e後邊附加上debug true後執行即可。更加詳細的內容可以看InstrumentationTestRunner的Javadoc。我希望Android能儘快有正式的文件來介紹這個內容。 如何在Android的單元測試中做標記?

在android.test.annotation包裡定義了幾個annotation,包括 @LargeTest,@MediumTest,@SmallTest,@Smoke,和@Suppress。你可以根據自己的需要用這些 annotation來對自己的測試分類。在執行單元測試命令時,可以在-e引數後設定“size large”/ “size medium”/ “size small”來執行具有相應標記的測試。特別的@Supperss可以取消被標記的Test的執行。 完整的操作過程

總結以上所有的內容,編寫並執行完整的測試需要以下的步驟:


以上步驟中,在Android自帶的例子中,我發現它有兩個manifest.xml。也就是說在步驟3中原始碼和測試程式碼分別生成了兩個不同的包。然後步驟4利用adb install命令安裝到了虛擬機器上。由於我沒有找到Eclipse ADT有辦法可以為一個只有Instrumentation,沒有Activity的Application打包並安裝,於是採用了略微不同的辦法完成了這個工作。下面將一一詳細介紹整個過程。 1. 編寫程式

我新建了一個專案TestApp,引數為:

Java程式碼
Package Name: com.android.testapp  

Activity Name: MainActivity

Application Name: TestApp

以下是MainActivity的原始碼:

package com.android.testapp;

import android.app.Activity;

import android.os.Bundle;

public class MainActivity extends Activity {

/** Called when the activity is first created. */

@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.main);

}

public int sum(int a, int b) {

return a + b;

}

public int substract(int a, int b) {

return b - a;

}

}


其中,我故意將減法的a – b寫成了b – a。 2. 編寫測試程式

然後,我新建了一個Source Folder,名為test,並在裡面新建了包com.android.testapp.test。並定義了一個TestCase,名為TestMainActivity,原始碼如下:

Java程式碼
package com.android.testapp.test;  

import com.android.testapp.MainActivity;

import android.test.ActivityInstrumentationTestCase;

import android.test.suitebuilder.annotation.MediumTest;

public class TestMainActivity extends ActivityInstrumentationTestCase<MainActivity> {

public TestMainActivity() {

super("com.android.testapp", MainActivity.class);

}

public TestMainActivity(String pkg, Class<MainActivity> activityClass) {

super(pkg, activityClass);

}

@MediumTest

public void testSum() {

assertEquals(3, getActivity().sum(1, 2));

}

@MediumTest

public void testSubstract() {

assertEquals(-1, getActivity().substract(1, 2));

}

}


我繼承了ActivityInstrumentationTestCase。這個TestCase在執行時會自動幫我啟動相應的Activity。

接下來就是程式的Manifest:

Java程式碼
<?xml version="1.0" encoding="utf-8"?>  

<manifest xmlns:android="http://schemas.android.com/apk/res/android"

package="com.android.testapp"

android:versionCode="1"

android:versionName="1.0.0">

<application android:icon="@drawable/icon" android:label="@string/app_name">

<activity android:name=".MainActivity"

android:label="@string/app_name">

<intent-filter>

<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />

</intent-filter>

</activity>

<uses-library android:name="android.test.runner" />

</application>

<instrumentation android:targetPackage="com.android.testapp" android:name="android.test.InstrumentationTestRunner" android:label="Test Unit Tests"></instrumentation>

</manifest>

在這個檔案中,我將Activity和Instrumentation的宣告寫到了一起,而沒有像Apis Demo那樣分開。請注意裡面的<uses-library>標籤。如果沒有那句,在執行測試時會報告找不到TestRunner。這是由於 Android在build的時候只把需要的東西打包,所以你必須明確的告訴Android Builder這一點。 3. Build和Install

在Eclipse上,這兩個步驟是一起完成的。只要點一下Run即可。只不過如果你不在Run Configuration裡將安裝後的Launch Action設為“Do Nothing”,就會自動執行一下你的MainActivity。對於我們,設為Do Nothing即可。如下圖:


完成後,利用命令

Java程式碼
adb shell pm list packages



可以在已經安裝的pkg列表裡看到com.android.testapp。 4. 執行測試,檢視結果

之後就開啟命令列,執行以下命令
Java程式碼
adb shell am instrument –e class com.android.testapp.test.TestMainActivity –w com.android.testapp/android.test.InstrumentationTestRunner 



即可看到如下的結果:

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


(三) 轉
Android下使用JUnit
Andorid下使用Junit測試框架,是步入正規的Androdid開發的必經之路,在Junit中可以得到元件,可以模擬傳送事件,檢測程式處理的正確性,下面就開始我們的教程:
工具:
1、Android1.5 SDK
2、ADT 0.9
3、Eclipse
需要的知識:
1、 Android開發的基礎
2、Junit的基礎
一、
首先建立工程:
目錄:
選中的test source folder是測試類的包,包名隨便,但是在配置Manifest.xml要注意
二、配置\layout\main.xml檔案,加入兩個button元件,程式碼如下:

Java程式碼
* <?xml version="1.0" encoding="utf-8"?>  
* <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
* android:orientation="vertical" android:layout_width="fill_parent"
* android:layout_height="fill_parent">
* <Button android:text="Button01" android:id="@+id/Button01"
* android:layout_width="wrap_content" android:layout_height="wrap_content"></Button>
* <Button android:text="Button02" android:id="@+id/Button02"
* android:layout_width="wrap_content" android:layout_height="wrap_content"></Button>
* </LinearLayout>


三、被測試的Activity程式碼
Java程式碼
# package cc.androidos.activity;  
# import android.app.Activity;
# import android.os.Bundle;
# import android.widget.Button;
# public class NewActivity extends Activity {
# /** Called when the activity is first created. */
# @Override
# public void onCreate(Bundle savedInstanceState) {
# super.onCreate(savedInstanceState);
# setContentView(R.layout.main);
# }
# public int add(int a , int b){
# return a+b;
# }
# }



四、測試NewActivity程式碼,這裡要繼承ActivityInstrumentationTestCase2,ActivityInstrumentationTestCase2是TestCase的子類

Java程式碼
* package cc.andoridos.activity.test;
   * import cc.androidos.activity.NewActivity;  
* import cc.androidos.activity.R;
* import android.test.ActivityInstrumentationTestCase2;
* import android.util.Log;
* import android.view.KeyEvent;
* import android.widget.Button;
* public class TestNewActivity extends
* ActivityInstrumentationTestCase2<NewActivity> {
* private Button button1 = null;
* private Button button2 = null;
* private NewActivity newActivity = null;
* public TestNewActivity() {
* super("cc.androidos.activity", NewActivity.class);
* //This first parameter should the Activity package
* //if other , the junit give us the exception: unable resolve the activity
* }
*
* @Override
* protected void setUp() throws Exception {
* String tag = "setUp";
* Log.e(tag, "init all var....");
* newActivity = getActivity();
* button1 = (Button) newActivity.findViewById(R.id.Button01);
* button2 = (Button) newActivity.findViewById(R.id.Button02);
* }
* /**
* * Testing the button is focused or not
* */
* public void testButtonFocus() {
* String tag = "testButtonFocus";
* Log.e(tag, "start the button focus...");
* assertTrue("Button1 is focused", button1.isFocused());
* Log.e(tag, "send the down key event...");
* sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
* assertTrue("Button2 is focused", button2.isFocused());
* }
*
* /**
* * Testing the add method in actvity
* */
* public void testAdd(){
* String tag ="testAdd";
* Log.e(tag, "Test the add method in NewActivity...");
* int i = newActivity.add(2, 5);
* assertEquals(7, i);
* }
*
* }



五、配置Manifest.xml檔案

Java程式碼
* <?xml version="1.0" encoding="utf-8"?>  
* <manifest xmlns:android="http://schemas.android.com/apk/res/android"
* package="cc.androidos.activity" android:versionCode="1"
* android:versionName="1.0">
* <application android:icon="@drawable/icon" android:label="@string/app_name">
* <activity android:name=".NewActivity" android:label="@string/app_name">
* <intent-filter>
* <action android:name="android.intent.action.MAIN" />
* <category android:name="android.intent.category.LAUNCHER" />
* </intent-filter>
* </activity>
* <activity android:name=".NewActivity2" android:label="@string/app_name">
* </activity>
* <uses-library android:name="android.test.runner" />
* <!-- Loading test library -->
* </application>
* <uses-sdk android:minSdkVersion="3" />
*
* <!-- 這個是關鍵,android:targetPackage="cc.androidos.activity"要測試的包,android:name="android.test.InstrumentationTestRunner" 用於跑TestCase的類-->
* <instrumentation android:targetPackage="cc.androidos.activity"
* android:label="Test New Activty" android:name="android.test.InstrumentationTestRunner"></instrumentation>
* </manifest>


Java程式碼
# E:\android\android-sdk-windows-1.5_pre\tools>adb shell am instrument -w cc.andro
# idos.activity/android.test.InstrumentationTestRunner
# 如果你配置了Android環境變數,直接使用:
# adb shell am instrument -w cc.androidos.activity/android.test.InstrumentationTestRunner
# 語法:adb shell am instrument -w <被測試的類的包名>/android.test.InstrumentationTestRunner


此篇引用原文地址:http://mintelong.iteye.com/blog/460903,尊重作者以及版權

相關文章