Robotium 為專門測試 android ui 的 framework,詳細介紹參考官網
本篇介紹如何導入 Robotium,以及建立測試 Activity 的 Robotium 模板,最後是 Robotium 常用函式介紹。


如何導入 Robotium

  1. Robotium 的使用環境和 android test project 非常類似,因此先建立 android test project。
    建立 android test project 詳細步驟請參考這篇
  2. 在第1步建立的 android test project 根目錄中建立 libs 資料夾,並將 Robotium 提供的 jar 檔放入 libs ,android 會自動幫你做好其他事。

建立測試 Activity 的 Robotium 模板

完成導入 Robotium 之後,你應該有個 test case,再將以下的 mSolo 加入。
Solo 為 Robotium 提供的類別,大部分測試功能都由它開始。

public class MainActivityTest extends ActivityInstrumentationTestCase2<MainActivity>
{
    private Solo mSolo;
    public MainActivityTest(String name) {
        super(MainActivity.class);
        setName(name);
    }
    public MainActivityTest()
    {
        this(MainActivityTest.class.getSimpleName());
    }
    protected void tearDown() throws Exception
    {
        mSolo.finishOpenedActivities();
        super.tearDown();
    }
    protected void setUp() throws Exception
    {
        super.setUp();
        mSolo = new Solo(getInstrumentation(), getActivity());
    }
    public void testPreconditions()
    {
       assertNotNull(mSolo);
    }
}

第24行初始化 mSolo
第17行銷毀 mSolo
以上就是測試 activity 的 Robotium 模板


Robotium 常用函式介紹

使用 Robotium 來寫測試主要分為3個步驟:

  1. 取得 UI Component
  2. 操作 UI Component
  3. 使用斷言(Assert)判斷操作結果是否符合預期

接下來依序介紹在 Robotium 中各個步驟如何進行

取得 UI Component

在 Robotium 主要有2種取得 UI Component 的方式,第1種為根據 UI Component 的 ID 來取得,適合用於 UI Component 具有唯一的 ID 情況。

android.view.View getView(int id)

Returns a View matching the specified resource id.
android.view.View getView(String id)

Returns a View matching the specified resource id.

Example

...
LinearLayout mainView = (LinearLayout) mSolo.getView(R.id.main_view);//R.id.main_view 為 resource id

UI Component 的內容值可以當作識別的方式,但這種方式只支援 Button, EditText, TextView, 適合用於 UI Component 具有內容值的情況。

android.widget.Button getButton(String text)

Returns a Button displaying the specified text.
android.widget.EditText getEditText(String text)

Returns an EditText displaying the specified text.
android.widget.TextView getText(String text)

Returns a TextView displaying the specified text.

Example

...
Button exitButton = mSolo.getButton("Exit");//Exit 為顯示在 button 上的內容

UI Component 的 Tag 可以當作識別的方式,適合用於 UI Component 具有 Tag 的情況下。

android.view.View getView(Object tag)

Returns a View matching the specified tag.

第2種為根據 UI Component 的類型進行過濾再根據索引來取得,這種情況適用於 UI Component 沒有可以識別的 ID 情況。以下第1個方法為回傳所有類型的 views, 第2個回傳指定類型的 views, 第3個回傳指定類型並指定 parent 的 views

ArrayList<android.view.View> getCurrentViews()

Returns an ArrayList of the Views currently displayed in the focused Activity or Dialog.
<T extends android.view.View>
ArrayList<T>
getCurrentViews(Class<T> classToFilterBy)

Returns an ArrayList of Views matching the specified class located in the focused Activity or Dialog.
<T extends android.view.View>
ArrayList<T>
getCurrentViews(Class<T> classToFilterBy, android.view.View parent)

Returns an ArrayList of Views matching the specified class located under the specified parent.

使用上述的方法取得 view 的群集之後,再使用以下方法取得個別的 view。
需要注意的是 index 該 index 為子視圖的順序(index 從零開始由左到右或上到下遞增)

android.widget.Button getButton(int index)

Returns a Button matching the specified index.
android.widget.EditText getEditText(int index)

Returns an EditText matching the specified index.
android.widget.ImageView getImage(int index)

Returns an ImageView matching the specified index.
android.widget.ImageButton getImageButton(int index)

Returns an ImageButton matching the specified index.
android.widget.TextView getText(int index)

Returns a TextView matching the specified index.
<T extends android.view.View>
T
getView(Class<T> viewClass, int index)

Returns a View matching the specified class and index.

Example

...
LinearLayout mainView = (LinearLayout) mSolo.getView(R.id.main_view);
List<Button> buttons = mSolo.getCurrentViews(Button.class, mainView);
for (int i=0; i<buttons.size(); ++i) {
    Button button = mSolo.getButton(i);
}
//以上的 source code 即是取得 mainView 中的所有 button

操作 UI Component

Robotium 提供的操作共有點擊,長按,輸入文字,拖曳,滾動,搜尋,等待。
點擊&長按
點擊和長按的方法大致上各為clickOnXXX, clickLongOnXXX,支援的種類有 View, Button, EditText, ImageView, ImageButton, CheckBox, MenuItem, RadioButton, ToggleButton, Screen座標等等 。
詳細參考官網
Example :

...
mSolo.clickOnButton("Exit");//點擊 Exit button

輸入和清除文字
各為 typeText 以及 enterText,都是對 EditText 輸入文字,2者不同為 type 會一個一個的輸入,而 enter 為直接全部輸入 ,清除則是只對 EditText 清除 (cleanEditText)。
詳細參考官網
Example :

...
EditText numberEditText = mSolo.getEditText("number");//取得內容為 number 的 EditText
mSolo.typeText(numberEditText, "123");//在 EditText 填入 123

拖曳

void drag(float fromX, float toX, float fromY, float toY, int stepCount)

Simulate touching the specified location and dragging it to a new location.
...
mSolo.drag(0.0f, 50.0f, 0.0f, 50.0f, 100);

需要注意的是原點從左上角開始算起。
滾動
滾動為 ScrollXXX,基本的有 ScrollDown, ScrollUp 往上下滾動一段。
ScrollToBottom, ScrollToTop 往頂端底端滾動。
ScrollToSide 滾動至左或右。進階可以指定滾動的距離。
支援的種類有 view, ListView, RecyclerView,
詳細參考官網

mSolo.scrollDown();

搜尋
searchXXX,搜尋的目的為確認 UI Compenent 是否存在於 Screen 上,有的話才進行下一步操作。支援 Button, EditText, TextView, ToggleButton, 詳細參考官網
Example :

...
if(!mSolo.searchButton("Exit")){//尋找 Exit button 是否在螢幕上
    fail("Exit button should on screen");
}

等待
waitForXXX為等待系列,支援 activity, dialog open dialog close, text, view。
需要注意的是 waitFor 函式會在其內預設等待20秒,在20秒之內若等待條件成立的話回傳 true,反之回傳 false,也有提供自定義時間 e.g. mSolo.waitForLogMessage(“”,5000)。
比較特殊等待條件有 waitForLogMessage,這裡的 LogMessage 即為使用 Log 列印出來的內容
e.g. Log.d(TAG,”log message should print”);
就可使用 mSolo.waitForLogMessage(“log message should print”);
另一個是 waitForCondition , 可以自定義複雜條件以滿足特別的需求。
詳細參考官網
另外還有其他操作 e.g. 休息(sleep),擷圖(takeScreenShot),模擬按下實體按鍵, 檢查 UI 狀態(isXXX)。


使用斷言(Assert)判斷操作結果是否符合預期

因為 android test project 預設為使用 junit 來斷言,對於絕大部分的斷言情況來說已經足夠。Robotium 提供的斷言不多,只有4種(assertCurrentAcitvity, assertMemoryNotLow)。
Example :

...
assertTrue(mSolo.searchButton("Exit"));//斷言 Exit button 需要在螢幕上