android單元測試

  1. 原文http://blog.csdn.net/stevenhu_223/article/details/8298858

                                                       http://download.csdn.net/detail/stevenhu_223/4895796

  本文是在上一篇文章《java單元測試》的基礎上繼續講解android的單元測試,android源碼中引入了java單元測試的框架(android源碼目錄:libcore\junit\src\main\java\junit\framework中可見),然後在java單元測試框架的基礎上擴展屬於android自己的測試框架。android具體框架類的關係圖如下:

    

    從上圖的類關係圖中可以知道,通過android測試類可以實現對android中相關重要的組件進行測試(如Activity,Service,ContentProvider,甚至是application)。

 其實在android源碼中,基本上每個系統應用都自帶一個測試工程,如下圖的源碼中settings(設置)模塊:

上圖的tests文件夾中就是settings模塊自帶的單元測試工程,有興趣的讀者可自行去研讀一下源代碼。

 

eclipse下(當然,前提是要保證eclipse中相關的android環境已經搭建好)進行android單元測試:

 

1.Application的測試:

   新建一個android項目,在該android項目添加一個繼承Application的類,代碼如下:

[java] view plaincopy
  1. package com.phicomm.hu;  
  2.   
  3. import android.app.Application;  
  4.   
  5. public class FxAndroidApplication extends Application  
  6. {  
  7.   
  8.     @Override  
  9.     public void onCreate()   
  10.     {  
  11.         // TODO Auto-generated method stub  
  12.         super.onCreate();  
  13.     }  
  14.   
  15.     @Override  
  16.     public void onTerminate()   
  17.     {  
  18.         // TODO Auto-generated method stub  
  19.         super.onTerminate();  
  20.     }  
  21.       
  22.     public String getFavourite()  
  23.     {  
  24.         return "I Love Java";  
  25.     }  
  26.   
  27. }  

 

 Appication類創建好後,接着創建對應的測試工程選中其所在的android工程---->鼠標右鍵----->new---->Android Test Project----->輸入測試工程名--->next----->選擇被測試的目標android工程(此處爲FxAndroidApplication所在的android工程)。這樣,一個測試工程就創建完成了。

    通過eclipse創建自動生成的測試工程項目和android工程項目結構上沒什麼大的區別,主要是在AndroidManifest.xml中有變化,如下:

[html] view plaincopy
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <manifest xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     package="com.phicomm.hu.test"  
  4.     android:versionCode="1"  
  5.     android:versionName="1.0" >  
  6.   
  7.     <uses-sdk android:minSdkVersion="10" />  
  8.   
  9.     <instrumentation  
  10.         android:name="android.test.InstrumentationTestRunner"  
  11.         android:targetPackage="com.phicomm.hu" />  
  12.   
  13.     <application  
  14.         android:icon="@drawable/ic_launcher"  
  15.         android:label="@string/app_name" >  
  16.         <uses-library android:name="android.test.runner" />  
  17.     </application>  
  18.   
  19. </manifest>  


在AndroidManifest.xml註冊了相關的測試環境(這些是android獨有的):<uses-library android:name="android.test.runner" />實現使用相關的運行測試類庫,<instrumentation />中的targetPackage爲被測試類所在的包。

    接下來在測試工程中創建FxAndroidApplicationd的測試類,代碼如下:

    

[java] view plaincopy
  1. package com.phicomm.hu.test;  
  2.   
  3. import com.phicomm.hu.FxAndroidApplication;  
  4.   
  5. import android.app.Application;  
  6. import android.test.ApplicationTestCase;  
  7.   
  8. public class FxApplicationTest extends ApplicationTestCase<FxAndroidApplication>   
  9. {  
  10.   
  11.     private FxAndroidApplication AppTest;  
  12.     public FxApplicationTest()  
  13.     {  
  14.         //調用父類構造函數,且構造函中傳遞的參數爲被測試的類  
  15.         super(FxAndroidApplication.class);  
  16.     }  
  17.   
  18.     @Override  
  19.     protected void setUp() throws Exception  
  20.     {  
  21.         // TODO Auto-generated method stub  
  22.         super.setUp();  
  23.         //獲取application之前必須調用的方法  
  24.         createApplication();  
  25.         //獲取待測試的FxAndroidApplication  
  26.         AppTest = getApplication();  
  27.     }  
  28.       
  29.     //測試FxAndroidApplication的getFavourite方法  
  30.     public void testGetFavourite()  
  31.     {  
  32.         /*驗證預測值"I Love C++"是否等於實際值, 
  33.         由於實際值爲"I love Java",所以此處測試結果爲Failure*/  
  34.         assertEquals("I Love C++", AppTest.getFavourite());  
  35.     }  
  36.       
  37. }  


  測試類創建好後,就可以實現對FxAndroidApplicationd進行測試了。

  測試方法:

   啓動android模擬器(也可以通過android手機)----->運行android工程----->在測試工程中選中測試類FxApplicationTest---->鼠標右鍵--->Run As---->Android Junit Test。這樣,測試結果就可以在eclipse的Junit視圖上顯示了,如下圖:

  

通過上圖的測試結果可知,ApplicationTestCase測試類中有兩個測試方法是默認進行測試的(testGetFavourite纔是我們要測試的方法)。

   當然,還可以通過adb進行測試連接android手機------>打開電腦命令窗口(開始-->運行--->輸入cmd)---->在命令窗口輸入adb shell---->am instrument -w com.phicomm.hu.test(測試用例所在的包名)/android.test.InstrumentationTestRunner。

 

2.Activity的測試:

 

   和上面application一樣,先創建一個android工程,該工程中創建了兩個activity,一個activity實現輸入用戶信息的登錄界面,另一個acticity顯示輸入的用戶信息。

   效果圖如下:

  

   登錄界面FxLoginActivity的代碼如下:

  

[java] view plaincopy
  1. package com.phicomm.hu;  
  2.   
  3. import android.app.Activity;  
  4. import android.content.Intent;  
  5. import android.os.Bundle;  
  6. import android.view.View;  
  7. import android.view.View.OnClickListener;  
  8. import android.widget.Button;  
  9. import android.widget.EditText;  
  10.   
  11. public class FxLoginActivity extends Activity   
  12. {  
  13.       
  14.     private EditText userName;  
  15.     private EditText passWord;  
  16.       
  17.     /** Called when the activity is first created. */  
  18.     @Override  
  19.     public void onCreate(Bundle savedInstanceState)   
  20.     {  
  21.         super.onCreate(savedInstanceState);  
  22.         setContentView(R.layout.main);  
  23.           
  24.         userName = (EditText)findViewById(R.id.name);  
  25.         passWord = (EditText)findViewById(R.id.psd);  
  26.           
  27.         Button login = (Button)findViewById(R.id.login);  
  28.         Button reset = (Button)findViewById(R.id.reset);  
  29.            
  30.          //監聽登錄按鈕  
  31.          login.setOnClickListener(new OnClickListener() {  
  32.               
  33.             @Override  
  34.             public void onClick(View v)   
  35.             {  
  36.                 // TODO Auto-generated method stub  
  37.                 Intent intent = new Intent(FxLoginActivity.this, FxResultActivity.class);                 
  38.                 //通過intent傳遞登錄信息到ResultActivity的界面中顯示  
  39.                 intent.putExtra("userName", userName.getText().toString());  
  40.                 intent.putExtra("passWord", passWord.getText().toString());  
  41.                 //啓動ResultActivity顯示登錄界面信息  
  42.                 startActivity(intent);  
  43.             }  
  44.         });  
  45.            
  46.          //監聽重置按鈕          
  47.          reset.setOnClickListener(new OnClickListener()   
  48.          {  
  49.               
  50.             @Override  
  51.             public void onClick(View v)   
  52.             {  
  53.                 // TODO Auto-generated method stub  
  54.                 resetInput();  
  55.             }  
  56.         });  
  57.     }  
  58.       
  59.     public void resetInput()  
  60.     {  
  61.         userName.setText("");  
  62.         passWord.setText("");  
  63.     }  
  64. }  


main.xml佈局文件的代碼如下:

 

[html] view plaincopy
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     android:layout_width="fill_parent"  
  4.     android:layout_height="fill_parent"  
  5.     android:orientation="vertical" >  
  6.   
  7.     <EditText   
  8.         android:id="@+id/name"  
  9.         android:layout_width="fill_parent"  
  10.         android:layout_height="wrap_content"  
  11.         android:hint="@string/name"/>  
  12.       
  13.      <EditText   
  14.         android:id="@+id/psd"  
  15.         android:layout_width="fill_parent"  
  16.         android:layout_height="wrap_content"  
  17.         android:hint="@string/psd"/>  
  18.        
  19.      <LinearLayout   
  20.          android:orientation="horizontal"  
  21.          android:layout_width="match_parent"  
  22.          android:layout_height="wrap_content"  
  23.          >  
  24.            
  25.          <Button   
  26.              android:id="@+id/login"  
  27.              android:layout_width="fill_parent"  
  28.              android:layout_height="wrap_content"  
  29.              android:layout_weight="1"  
  30.              android:text="@string/login"/>  
  31.            
  32.           <Button   
  33.              android:id="@+id/reset"  
  34.              android:layout_width="fill_parent"  
  35.              android:layout_height="wrap_content"  
  36.              android:layout_weight="1"  
  37.              android:text="@string/reset"/>  
  38.            
  39.      </LinearLayout>  
  40.   
  41. </LinearLayout>  


顯示用戶信息界面的FxResultActivity代碼如下:

[java] view plaincopy
  1. package com.phicomm.hu;  
  2.   
  3. import android.app.Activity;  
  4. import android.content.Intent;  
  5. import android.os.Bundle;  
  6. import android.util.Log;  
  7. import android.widget.EditText;  
  8. import android.widget.TextView;  
  9.   
  10. public class FxResultActivity extends Activity   
  11. {  
  12.   
  13.       
  14.     private static final String TAG = "ResultActivity";  
  15.     @Override  
  16.     protected void onCreate(Bundle savedInstanceState)   
  17.     {  
  18.         // TODO Auto-generated method stub  
  19.         super.onCreate(savedInstanceState);  
  20.         setContentView(R.layout.result);  
  21.           
  22.         TextView result = (TextView)findViewById(R.id.result);  
  23.         //通過得到intent獲取登錄界面傳來的信息  
  24.         Intent intent = getIntent();  
  25.         String userName = intent.getStringExtra("userName");  
  26.         String passWord = intent.getStringExtra("passWord");  
  27.         //將登錄信息在頁面中顯示  
  28.         result.setText("用戶名:" + userName + "\n" + "密碼:" + passWord);      
  29.     }  
  30.   
  31.       
  32. }  

 

  以上的android工程創建好後,創建一個對應的測試工程:

  測試工程中對應的FxLoginActivity類的測試代碼如下(詳細的代碼講解見代碼中的相關注釋,這裏不在累贅):

  

[java] view plaincopy
  1. package com.phicomm.hu.test;  
  2.   
  3.   
  4.   
  5. import android.app.Instrumentation;  
  6. import android.test.ActivityInstrumentationTestCase2;  
  7. import android.view.KeyEvent;  
  8. import android.widget.Button;  
  9. import android.widget.EditText;  
  10.   
  11. import com.phicomm.hu.FxLoginActivity;  
  12.   
  13. public class FxLoginActivityTest extends ActivityInstrumentationTestCase2<FxLoginActivity>   
  14. {  
  15.   
  16.     private Instrumentation mInstrumentation;  
  17.     private FxLoginActivity mLoginTest;  
  18.       
  19.     private EditText userName;  
  20.     private EditText passWord;  
  21.     private Button login;  
  22.     private Button reset;  
  23.       
  24.     public FxLoginActivityTest()  
  25.     {  
  26.         super(FxLoginActivity.class);  
  27.     }  
  28.   
  29.     //重寫setUp方法,在該方法中進行相關的初始化操作  
  30.     @Override  
  31.     protected void setUp() throws Exception   
  32.     {  
  33.         // TODO Auto-generated method stub  
  34.         super.setUp();  
  35.         /**這個程序中需要輸入用戶信息和密碼,也就是說需要發送key事件, 
  36.          * 所以,必須在調用getActivity之前,調用下面的方法來關閉 
  37.          * touch模式,否則key事件會被忽略 
  38.          */  
  39.         //關閉touch模式  
  40.         setActivityInitialTouchMode(false);  
  41.         mInstrumentation = getInstrumentation();  
  42.         //獲取被測試的FxLoginActivity  
  43.         mLoginTest = getActivity();  
  44.           
  45.         //獲取FxLoginActivity相關的UI組件  
  46.         userName = (EditText)mLoginTest.findViewById(com.phicomm.hu.R.id.name);  
  47.         passWord = (EditText)mLoginTest.findViewById(com.phicomm.hu.R.id.psd);  
  48.         login = (Button)mLoginTest.findViewById(com.phicomm.hu.R.id.login);  
  49.         reset = (Button)mLoginTest.findViewById(com.phicomm.hu.R.id.reset);       
  50.           
  51.     }  
  52.       
  53.     //該測試用例實現在測試其他用例之前,測試確保獲取的組件不爲空  
  54.     public void testPreConditions()  
  55.     {  
  56.         assertNotNull(mLoginTest);  
  57.         assertNotNull(userName);  
  58.         assertNotNull(passWord);  
  59.         assertNotNull(login);  
  60.         assertNotNull(reset);  
  61.     }  
  62.       
  63.     /**該方法實現在登錄界面上輸入相關的登錄信息。由於UI組件的 
  64.      * 相關處理(如此處的請求聚焦)需要在UI線程上實現, 
  65.      * 所以需調用Activity的runOnUiThread方法實現。 
  66.      */  
  67.     public void input()  
  68.     {  
  69.         mLoginTest.runOnUiThread(new Runnable()   
  70.         {  
  71.               
  72.             @Override  
  73.             public void run()   
  74.             {  
  75.                 // TODO Auto-generated method stub  
  76.                 userName.requestFocus();  
  77.                 userName.performClick();  
  78.             }  
  79.         });  
  80.         /*由於測試用例在單獨的線程上執行,所以此處需要同步application, 
  81.          * 調用waitForIdleSync等待測試線程和UI線程同步,才能進行輸入操作。 
  82.          * waitForIdleSync和sendKeys不允許在UI線程裏運行 
  83.          */  
  84.         mInstrumentation.waitForIdleSync();  
  85.           
  86.         //調用sendKeys方法,輸入用戶名  
  87.         sendKeys(KeyEvent.KEYCODE_P, KeyEvent.KEYCODE_H,  
  88.                 KeyEvent.KEYCODE_I, KeyEvent.KEYCODE_C,  
  89.                 KeyEvent.KEYCODE_O, KeyEvent.KEYCODE_M,  
  90.                 KeyEvent.KEYCODE_M);  
  91.           
  92.         mLoginTest.runOnUiThread(new Runnable()   
  93.         {  
  94.               
  95.             @Override  
  96.             public void run()   
  97.             {  
  98.                 // TODO Auto-generated method stub  
  99.                 passWord.requestFocus();  
  100.                 passWord.performClick();  
  101.             }  
  102.         });  
  103.           
  104.         //調用sendKeys方法,輸入密碼  
  105.         sendKeys(KeyEvent.KEYCODE_1, KeyEvent.KEYCODE_2,   
  106.                 KeyEvent.KEYCODE_3, KeyEvent.KEYCODE_4);  
  107.     }  
  108.       
  109.     //測試輸入的用戶信息  
  110.     public void testInput()  
  111.     {  
  112.         //調用測試類的input方法,實現輸入用戶信息(sendKeys實現輸入)  
  113.         input();  
  114.         //測試驗證用戶信息的預期值是否等於實際值  
  115.         assertEquals("phicomm", userName.getText().toString());  
  116.         //密碼的預期值123與實際值1234不符,Failure;  
  117.         assertEquals("123", passWord.getText().toString());  
  118.     }  
  119.       
  120.     //測試登錄按鈕  
  121.     public void testLogin()  
  122.     {  
  123.         input();  
  124.         //開新線程,並通過該線程在實現在UI線程上執行操作  
  125.         mInstrumentation.runOnMainSync(new Runnable()   
  126.         {  
  127.               
  128.             @Override  
  129.             public void run()   
  130.             {  
  131.                 // TODO Auto-generated method stub  
  132.                 login.requestFocus();  
  133.                 login.performClick();  
  134.             }  
  135.         });  
  136.     }  
  137.       
  138.     //測試重置按鈕  
  139.     public void testReset()  
  140.     {  
  141.         input();  
  142.         mInstrumentation.runOnMainSync(new Runnable()   
  143.         {  
  144.               
  145.             @Override  
  146.             public void run()   
  147.             {  
  148.                 // TODO Auto-generated method stub  
  149.                 reset.requestFocus();  
  150.                 //點擊按鈕  
  151.                 reset.performClick();  
  152.             }  
  153.         });  
  154.         //驗證重置按鈕的實現功能,是否點擊後內容爲空  
  155.         assertEquals("", userName.getText().toString());  
  156.         assertEquals("", passWord.getText().toString());  
  157.     }  
  158. }  

 

  運行該測試類進行測試(選中---->Run As--->Android Junit Test),然後會自動啓動模擬器進行相關的輸入點擊測試。注:測試時可以發現,程序在測試到testLogin()方法登錄到另一個界面時,測試就停止了,也就是說testReset()沒測試到。所以,需要測試testReset()時可以先把testLogin()註釋掉,不然程序會測試到testLogin()後就不在對testReset()進行測試。

 

FxResultActivity的測試類代碼如下:

[java] view plaincopy
  1. package com.phicomm.hu.test;  
  2.   
  3. import android.content.Intent;  
  4. import android.test.ActivityInstrumentationTestCase2;  
  5. import android.widget.TextView;  
  6.   
  7. import com.phicomm.hu.FxResultActivity;  
  8.   
  9. public class FxResultActivityTest extends ActivityInstrumentationTestCase2<FxResultActivity>   
  10. {  
  11.   
  12.     private static final String LOGIN_INFO = "用戶名:feixun\n密碼:123";  
  13.       
  14.     private FxResultActivity mResultActivity;  
  15.     private TextView result;  
  16.       
  17.     public FxResultActivityTest()  
  18.     {  
  19.         super(FxResultActivity.class);  
  20.     }  
  21.   
  22.     @Override  
  23.     protected void setUp() throws Exception   
  24.     {  
  25.         // TODO Auto-generated method stub  
  26.         super.setUp();  
  27.         //創建Intent,通過Intent傳遞用戶的登錄信息  
  28.         Intent intent = new Intent();  
  29.         intent.putExtra("userName""feixun");  
  30.         intent.putExtra("passWord""123");  
  31.         //通過攜帶用戶登錄信息的intent啓動FxResultActivity  
  32.         mResultActivity = launchActivityWithIntent("com.phicomm.hu",   
  33.                 FxResultActivity.class, intent);  
  34.         //獲取UI組件  
  35.         result = (TextView)mResultActivity.findViewById(com.phicomm.hu.R.id.result);  
  36.     }  
  37.       
  38.     //測試驗證用戶的登錄信息  
  39.     public void testLoginInfo()  
  40.     {  
  41.         //驗證預期值是否等於實際值  
  42.         assertEquals(LOGIN_INFO, result.getText().toString());  
  43.     }  
  44.       
  45. }  


運行上面的測試類,結果正確


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章