Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> 使用Robolectric對Android應用進行單元測試

使用Robolectric對Android應用進行單元測試

編輯:關於Android編程

介紹Robolectric主要從框架簡介、框架優點、框架可行性分析,框架環境配置、框架演示、框架參考資料方面進行介紹:

一、框架簡介

官網的介紹
Running tests on an Android emulator or device is slow! Building, deploying, and launching the app often takes a minute or more. That’s no way to do TDD. There must be a better way.

Wouldn’t it be nice to run your Android tests directly from inside your IDE? Perhaps you’ve tried, and been thwarted by the dreaded java.lang.RuntimeException: Stub!?

Robolectric is a unit test framework that de-fangs the Android SDK jar so you can test-drive the development of your Android app. Tests run inside the JVM on your workstation in seconds. With Robolectric you can write tests like this:

我的理解是

對於Android app來說,寫起單元測試來瞻前顧後,一方面單元測試需要運行在模擬器上或者真機上,麻煩而且緩慢,另一方面,一些依賴Android SDK的對象(如Activity,TextView等)的測試非常頭疼,Robolectric可以解決此類問題,它的設計思路便是通過實現一套JVM能運行的Android代碼,從而做到脫離Android環境進行測試。

 

1、可以不運行於設備之上,可以想一想,一個項目小點還好,大一點的項目跑起來平時花費我們兩三分鐘,所以不錯哦。
2、使用Android的例子測試大多拋出java.lang.RuntimeException: Stub!?這個出錯信息,白了還是個運行的過程,所以如果你的unit test代碼裡面有android。

二、框架優點

測試驅動android開發

在安卓模擬器或者真機上跑測試用例速度很慢。構建、部署、啟動app,通常需要花費一分鐘或者更久。這不是TDD(測試驅動開發)模式.Robolectric提供一種更好的方式。

可能你一直嘗試在java IDE中使用junit或者testng直接跑測試用例,但是一直報java.lang.RuntimeException: Stub!異常。

這個異常是因為在jdk中沒有android運行環境。而現在Robolectric這款android單元測試工具,模擬了android sdk中的jar包,可以直接在jvm中運行測試用例,這樣就大大節省了時間。

SDK,Resource和Native Method模擬

Robolectric可以處理控件展示、資源加載和很多使用native C實現的真機上的其他功能。所以我們可以使用Robolectric來模擬真機上的大部分操作。我們可以很方便地獲取Robolectric的源碼,直接查看它的模擬機制,所以使用Robolectric,我們也可以模擬錯誤條件和一些真實的傳感器信號。

脫離模擬器執行測試用例

Robolectric允許我們在項目工程中或者持續集成(CI如hudson、jenkins)中使用jvm來執行測試用例,所以就省掉了打包、安裝的過程,將測試用例的執行時間由分鐘級降到秒級。

對比:

\

三、可行性分析

(1)環境配置相對簡單(根據後面介紹配置即可)
(2)可以直接在jvm中運行測試用例(包含Android相關類,打印日志等),這樣就大大節省了時間。
(3)Robolectric可以在持續集成(jenkins)中使用jvm來執行測試用例。
(4)Robolectric可以對(OrmLite,retrofit)網絡請求,數據庫進行測試。
(5)Robolectric相對比較成熟,使用起來簡單,官網有詳細的API文檔,一些難點與資料比較容易查找。
但是存在一些問題,

(1)只支持22版本以及以下,我測試了23,22,21,20,19。其中20,23不支持。(第一次運行測試自動下載一些Jar包)

\
(2)異步測試出現一些問題(比如改變一些編碼習慣,比如回調函數不能寫成匿名內部類對象,需要定義一個全局變量,並破壞其封裝性,即提供一個get方法,供UT調用),解決方案使用Mockito來結合進行測試,將異步轉為同步,後面參考資料有。
(3)遇到問題,作者很積極回答,詳情https://github.com/robolectric/robolectric/issues

四、框架環境配置

一、Gradle配置
在build.gradle中配置如下依賴關系:

\
二、在test目錄(如木有自己創建)
建立一個JustTest測試類
\
三、通過注解配置JustTest(測試類)

@RunWith(RobolectricGradleTestRunner.class)
@Config(constants = BuildConfig.class,sdk = 19)
public class JustTest {
請注意:sdk目前只適配(API21以及以下,可選擇21,19,16)
四、Android Studio的配置(2.0版本以上跳過這個步驟)
1、在Build Variants面板中,將Test Artifact切換成Unit Tests模式(目錄綠色表示成功),如下圖:

 

\
\
2、working directory 設置為$MODULE_DIR$
如果在測試過程遇見如下問題,解決的方式就是設置working directory的值:
java.io.FileNotFoundException: build\intermediates\bundles\debug\AndroidManifest.xml (系統找不到指定的路徑。)設置方法如下圖所示:
\
configurations

 

\

Working directory的配置

五、框架演示

Android 打印的日志輕松可以在控制台查看

 

@Before
public void setUp() throws URISyntaxException {
    //輸出日志
    ShadowLog.stream = System.out;
}

\

寫了一個創建Activity實例、Activity的跳轉,生命周期的測試,UI組件狀態,Toast信息驗證的測試用例

 

 

 //創建Activity實例
 @Test
 public void testActivity() {
     MainActivity sampleActivity = Robolectric.setupActivity(MainActivity.class);//創建Activity
     Assert.assertNotNull(sampleActivity);//判斷是否為空
     Assert.assertEquals(sampleActivity.getTitle(), "MainActivity");//獲取Activity的標題
 }

/* @Test
 public void testMainActivity() {
     MainActivity mainActivity = Robolectric.setupActivity(MainActivity.class);//創建Activity
     mainActivity.findViewById(R.id.tv_test).performClick();//自動點擊按鈕

     ShadowActivity shadowActivity = Shadows.shadowOf(mainActivity);//ShodawRobolectric的本質是在Java運行環境下,
     // 采用Shadow的方式對Android中的組件進行模擬測試,從而實現Android單元測試。對於一些Robolectirc暫不支持的組件,可以采用自定義Shadow的方式擴展Robolectric的功能。

     Intent expectedIntent = new Intent(mainActivity, TestActivity.class);
     Intent actualIntent = shadowActivity.getNextStartedActivity();
     Assert.assertEquals(expectedIntent, actualIntent);

     String hello = mainActivity.getResources().getString(R.string.app_name);
     Assert.assertEquals("My Application",hello);
 }*///這個網上很多人寫這個,我驗證是錯誤的。

 /**
  * 測試下一個Activity
  */
 @Test
 public void testNextActivity(){
     MainActivity mainActivity = Robolectric.setupActivity(MainActivity.class);
     mainActivity.findViewById(R.id.tv_test).performClick();
     ShadowActivity shadowActivity = Shadows.shadowOf(mainActivity);
     Intent nextStartedActivity = shadowActivity.getNextStartedActivity();
     ShadowIntent shadowIntent = Shadows.shadowOf(nextStartedActivity);
     Assert.assertEquals( shadowIntent.getIntentClass(), (TestActivity.class));
 }


 //測試生命周期
 @Test
 public void testLifecycle() {
     ActivityController activityController = Robolectric.buildActivity(MainActivity.class).create().start();
     Activity activity = activityController.get();
     TextView textview = (TextView) activity.findViewById(R.id.tv_test);
     Assert.assertEquals("onCreate",textview.getText().toString());
     activityController.resume();
     Assert.assertEquals("onResume", textview.getText().toString());
     activityController.destroy();
     Assert.assertEquals("onDestroy", textview.getText().toString());
 }
 //UI組件狀態
 @Test
 public void testViewState(){
     MainActivity mainActivity = Robolectric.setupActivity(MainActivity.class);
     CheckBox checkBox = (CheckBox) mainActivity.findViewById(R.id.box_test);
     Button testBt = (Button) mainActivity.findViewById(R.id.bt_test);
     Assert.assertTrue(testBt.isEnabled());

     checkBox.setChecked(true);
     //點擊按鈕,CheckBox反選
     testBt.performClick();
     Assert.assertTrue(!checkBox.isChecked());
     testBt.performClick();
     Assert.assertTrue(checkBox.isChecked());
 }

 //Toast
 @Test
 public void testToast(){
     //點擊按鈕,出現吐司
     MainActivity mainActivity = Robolectric.setupActivity(MainActivity.class);
     Button toastBt = (Button) mainActivity.findViewById(R.id.bt_toast);
     toastBt.performClick();
     Assert.assertEquals(ShadowToast.getTextOfLatestToast(),"we love UT");
 }
點擊右鍵,運行,注意第一次運行需要下載一些東西,所以很慢,最好翻牆或者設置代理

 

\

運行結果(成功)如下:

\

弄個失敗的例子,改了下一個Activity的跳轉,將TestActivity改成SecondActivity.代碼與運行結果如下:
\

運行結果顯示有錯誤,具體到行數與差異之處。

\

代碼地址:http://pan.baidu.com/s/1c2E4BUo

 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved