http://www.uml.org.cn/mobiledev/201305242.asp
在本文中,你將會學習到如何在Eclipse中創建Android JUnit的單元測試工程以及在不同的條件下創建及運行自動測試用例。
準備工作
本文假設讀者已經有一定的Android基礎知識,並且已經安裝了Eclipse和Android SDK等開發工具。本文將指導讀者如何將Android Junit框架應用到Android應用中去。本文還特別重點展示瞭如何測試Android中的Activity和如何識別程序中的錯誤。
步驟1 被測試的應用SimpleCalc概況
在本文中,將以一個寫好了的應用SimpleCalc簡單計算器爲例子進行講解。這個簡單計算器有兩個功能,允許用戶輸入兩個數並將它們相加或相乘,最後顯示結果,如下圖所示:
步驟2 SimpleCalc的的界面設計
由於應用比較簡單,只佔一屏,所以我們在/res/layout/main.xml中設計如下代碼所示:
<?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"> <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/hello" android:gravity="center_horizontal" android:textSize="48px" android:padding="12px" /> <EditText android:layout_height="wrap_content" android:id="@+id/value1" android:hint="@string/hint1" android:inputType="numberDecimal" android:layout_width="fill_parent" android:textSize="48px"></EditText> <EditText android:layout_height="wrap_content" android:id="@+id/value2" android:hint="@string/hint2" android:inputType="numberDecimal" android:layout_width="fill_parent" android:textSize="48px"></EditText> <FrameLayout android:id="@+id/FrameLayout01" android:layout_width="wrap_content" android:layout_height="wrap_content" android:padding="12px" android:background="#ff0000"> <LinearLayout android:id="@+id/LinearLayout02" android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="horizontal" android:background="#000000" android:padding="4px"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/resultLabel" android:textSize="48px" android:id="@+id/resultLabel"></TextView> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/result" android:textSize="48px" android:textStyle="bold" android:layout_marginLeft="16px"></TextView> </LinearLayout> </FrameLayout> <LinearLayout android:id="@+id/LinearLayout03" android:layout_height="wrap_content" android:layout_width="fill_parent"> <Button android:layout_height="wrap_content" android:id="@+id/addValues" android:text="@string/add" android:textSize="32px" android:layout_width="wrap_content"></Button> <Button android:layout_height="wrap_content" android:id="@+id/multiplyValues" android:text="@string/multiply" android:textSize="32px" android:layout_width="wrap_content"></Button> </LinearLayout> </LinearLayout> |
簡單解析一下這個界面設計,我們使用了LinearLayout,以使得控件能在垂直方向豎向排列。界面中包括了顯示標題“Unit Testing Sample”的textview,兩個輸入數字的edittext控件,一個FrameLayout控件中包含了一個水平的LinearLayout,在這個LinearLayout包含了一個顯示結果的textview以及其提示文字“Result”,注意的是FrameLayout的背景顏色設置爲紅色,而LinearLayou設置成了黑色背景。
步驟3 SimpleCale Activity
本程序中只有一個Actity:MainActity.java,代碼如下:
package com.mamlambo.article.simplecalc; import android.app.Activity; public class MainActivity extends Activity { final EditText value1 = (EditText) findViewById(R.id.value1); final TextView result = (TextView) findViewById(R.id.result); Button addButton = (Button) findViewById(R.id.addValues); public void onClick(View v) { Integer answer = val1 + val2; Button multiplyButton = (Button) findViewById(R.id.multiplyValues); public void onClick(View v) { Integer answer = val1 * val2; |
上面的代碼十分簡單,分別在兩個按鈕的onclick事件中,對用戶輸入的數進行了相加和相乘,看上去代碼似乎沒問題,但接下來,我們將通過Junit去發現其中的bug。
步驟4 創建Android 單元測試工程
可以有兩種方法去增加單元測試工程:一種是在創建新的Android工程時,在創建嚮導時同時創建單元測試工程,另外是針對已有的項目工程添加一個單元測試工程。本文由於已經有了一個項目工程,所以用如下步驟增加單元測試工程:
在Eclipse中,選擇存在的工程SimpleCalc,鼠標右鍵後在彈出的菜單中選擇Android Tools-àNew Test Project,如下圖所示:
步驟5 設置測試工程
接下來需要對單元測試的工程進行設置,我們採用如下的設置方法:
測試工程名稱:我們採用SimpleCalcTest
工程的位置:這個可以隨便設置
選擇被測試的工程:這裏我們選擇已經存在的SimpleCalc
構建的目標版本:這裏我們選擇Android 2.1
測試用例的包名:設置爲com.mamlambo.article.simplecalc.test,
設置界面如下圖所示:
步驟6 SimpleCalcTest單元測試項目的結構
我們審視下SimpleCalcTest的項目結構如下圖所示,可以看到這跟普通的Android工程沒什麼兩樣:
步驟7 創建單元測試用例
下面創建第一個單元測試用例,鼠標右鍵點擊simplecalc.test的包,在彈出的菜單中選擇NewàJUnit Test Case,如下圖所示:
步驟8 設置單元測試用例
接下來對單元測試進行如下設置
設置選擇使用Junit 3
源代碼目錄:這裏要設置爲SimpleCalcTest工程的代碼目錄
Package:這裏設置爲com.mamlambo.article.simplecalc.test,
測試用例名稱:設置爲MathValidation
測試的父類:這裏選擇“android.test.ActivityInstrumentationTestCase2.",這個是用來測試activity的Android的測試用例
將多選框中的setup,constructor兩個都勾選上
如下圖所示
步驟9 查看MatthValidation測試用例
在上圖中,點”Finish”按鈕後,MathVlidatiton.java測試用例就創建了。在單元測試中包括如下幾個部分:construction, setUp(), 針對方法的測試用例, tearDown(), 和destruction。在setup()方法中,主要是實現一些在測試工作前的資源及環境設置等的初始化設置;而針對方法的測試用例中,需要用戶自己編寫,一般是以“test+方法名”;而tearDown()在每個測試方法之後運行,用來撤消其初始化的測試環境。
代碼如下:
package com.mamlambo.article.simplecalc.test; import android.test.ActivityInstrumentationTestCase2; public class MathValidation extends ActivityInstrumentationTestCase2 { public MathValidation(String name) { super(name); } protected void setUp() throws Exception { super.setUp(); } } |
步驟10 修改MathValidation的構造函數
在測試用例的構造函數中,寫入如下代碼,以將我們正在使用的測試父類與測試環境設置進行綁定。
public MathValidation() { super("com.mamlambo.article.simplecalc", MainActivity.class); } |
步驟11 編寫setUp方法
現在可以收集數據去驗證SimpleCalc的計算方法了。在setUp方法中,首先應該通過getActivity()方法獲得當前的Activity,如下所示:
MainActivity mainActivity = getActivity(); |
接着,需要獲得名爲R.id.result的textview控件的實例,這個控件實際上保存計算器應用的運算結果的,代碼如下所示:
package com.mamlambo.article.simplecalc.test; import android.test.ActivityInstrumentationTestCase2; import android.widget.TextView; import com.mamlambo.article.simplecalc.MainActivity; import com.mamlambo.article.simplecalc.R; public class MathValidation extends ActivityInstrumentationTestCase2 { private TextView result; public MathValidation() { super ("com.mamlambo.article.simplecalc", MainActivity.class); } @Override protected void setUp() throws Exception { super.setUp(); MainActivity mainActivity = getActivity(); result = (TextView) mainActivity.findViewById(R.id.result); } } |
步驟12 SimpleCalc計算器中的加法測試用例
我們首先針對SimpleCalc中的加法進行測試用例的編寫。這個測試用例中,會輸入兩個數(24和74),並測試是否其結果等於98。爲了模擬在輸入數字後點按鈕的效果,我們使用了sendkeys方法,這個方法的優點在於可以在輸入後自動將焦點切換到下一個控件上。最後,我們使用assertTrue的斷言去判斷實際結果是否就是等於98,代碼如下:
private static final String NUMBER_24 = "2 4 ENTER "; private static final String NUMBER_74 = "7 4 ENTER "; private static final String ADD_RESULT = "98"; public void testAddValues() { sendKeys(NUMBER_24); // now on value2 entry sendKeys(NUMBER_74); // now on Add button sendKeys("ENTER"); // get result String mathResult = result.getText().toString(); assertTrue("Add result should be 98", mathResult.equals(ADD_RESULT)); } |
步驟13 改進測試用例
由於每次測試時,其實都是使用同一個activity的,因此在每次測試時不需要清除舊的值,我們可以在一個sendKeys()方法中,發送一系列的輸入命令,如下所示:
sendKeys(NUMBER_24 + NUMBER_74 + "ENTER"); |
我們測試一個小數的情況如下,看結果是否等於79.5
public void testAddDecimalValues() { sendKeys(NUMBER_5_DOT_5 + NUMBER_74 + "ENTER"); String mathResult = result.getText().toString(); assertTrue("Add result should be " + ADD_DECIMAL_RESULT + " but was " + mathResult, mathResult.equals(ADD_DECIMAL_RESULT)); } |
同樣,我們去編寫乘法的單元測試用例,這裏我們繼續使用sendKeys()方法,由於乘法的按鈕就在加法的按鈕右邊,所以我們在用sendkey模擬輸入了兩個數後,發送“DRAD_RIGHT”的消息,就可以了。
public void testMultiplyValues() { sendKeys(NUMBER_24+NUMBER_74+ " DPAD_RIGHT ENTER"); String mathResult = result.getText().toString(); assertTrue("Multiply result should be " + MULTIPLY_RESULT + " but was " + mathResult, mathResult.equals(MULTIPLY_RESULT)); } |
步驟14 在模擬器中運行單元測試
運行單元測試的方法很簡單,鼠標右鍵項目,在彈出的菜單中選擇“Debug ASàAndroid JUnit Test”即可,運行結果如下兩圖所示:
其中紅色的表示測試沒辦法通過,綠色的條狀表示測試已經通過。
步驟15 Android中對屏幕顯示的單元測試
在Android 的單元測試中,還可以針對界面的顯示位置等進行單元測試。比如我們在Eclipse時開發採用的界面模擬器是在800*480的模式下的,但如果在其他尺寸規格的移動設備上是否能正常運行呢?這就需要對界面設置部分進行單元測試了。
我們另外創建一個單元測試用例,用前文所講的方法新建立一個名爲LayoutTests的單元測試用例,如下圖:
並編寫如下代碼:
package com.mamlambo.article.simplecalc.test; import android.test.ActivityInstrumentationTestCase2; import android.view.View; import android.widget.Button; import com.mamlambo.article.simplecalc.MainActivity; import com.mamlambo.article.simplecalc.R; public class LayoutTests extends ActivityInstrumentationTestCase2 { private Button addValues; private Button multiplyValues; private View mainLayout; public LayoutTests() { super("com.mamlambo.article.simplecalc", MainActivity.class); } protected void setUp() throws Exception { super.setUp(); MainActivity mainActivity = getActivity(); addValues = (Button) mainActivity.findViewById(R.id.addValues); multiplyValues = (Button) mainActivity .findViewById(R.id.multiplyValues); mainLayout = (View) mainActivity.findViewById(R.id.mainLayout); } } |
這裏,分別獲得了加法按鈕和乘法按鈕的實例。接下來,增加一個testAddButtonOnScreen的方法,以測試按鈕的位置是否正確。在這個方法中,首先你要決定屏幕的大小。有很多方法去檢測屏幕的大小,比如用getWidth()和getHeight()方法,當然在考慮尺寸時,還必須考慮象標題欄,狀態欄等所佔用的位置大小。下面是其代碼:
public void testAddButtonOnScreen() { int fullWidth = mainLayout.getWidth(); int fullHeight = mainLayout.getHeight(); int[] mainLayoutLocation = new int[2]; mainLayout.getLocationOnScreen(mainLayoutLocation); int[] viewLocation = new int[2]; addValues.getLocationOnScreen(viewLocation); Rect outRect = new Rect(); addValues.getDrawingRect(outRect); assertTrue("Add button off the right of the screen", fullWidth + mainLayoutLocation[0] > outRect.width() + viewLocation[0]); assertTrue("Add button off the bottom of the screen", fullHeight + mainLayoutLocation[1] > outRect.height() + viewLocation[1]); } |
在各類尺寸的模擬器上運行,可以得到如下結果所示的測試結果:
480x800, portrait 模式 (通過) 800x480, landscape mode (失敗) 320x480, portrait mode (失敗) 480x320, landscape (失敗) 480x854, portrait mode (通過) 854x480, landscape mode (失敗)? |
大家可以思考下爲什麼有的測試用例成功有的失敗。
總結
本文講解了如何使用junit配合Android的應用進行單元測試及詳細步驟,以及如何在Junit測試Android時的小技巧。可以看到,在設計完應用後應該編寫單元測試用例,測試用例越多和越詳細,則對程序的正確性提高越有好處。