對於Android 單元測試來說, 若滿足以下測試條件, 可選用 SingleActivityTestCase 來測試
(1) 針對單一Activity 測試, 不涉及其他Activity交互作用.
如startActivityForResult 的返回結果做測試.
(2) 對UI進行自動化測試
(3) 只需要一次初始化 (setUp()) 與結束 (tearDown()), 亦即每個測試項目不會重複執行 setUp() 與 tearDown()
此測試類別和 ActivityUnitTestCase 相似, 只差在 ActivityUnitTestCase的每個測試項目會重複執行 setUp() 與 tearDown()
請參閱 Android ActivityUnitTestCase
@UiThreadTest 的順序會根據命名來決定順序
SingleActivityTestCase 運用範例
一個Activity中含有一個EditText, TextView, Button
EditText : 使用者輸入框
TextView : 呈現使用者輸入框的內容
Button : 點擊Button , 將EditText的內容呈現在TextView
Step 1: 建立測試檔
建立測試檔 MainActivityTest_Single_Launch extends SingleLaunchActivityTestCase
使用 Ctrl + Shift + T 建立測試檔, 並選擇 subclass 為 SingleLaunchActivityTestCase
位置儲存於 /src/androidTest/java/ package_path /
Step 2: 初始化
建立測試元件
1 2 3 4 5
| MainActivity mMainActivity;
private Button mTestButton; private EditText mEditText; private TextView mTextView;
|
建立Constructor
1 2 3
| public MainActivityTest_Single_Launch() { super("com.projects.nick", MainActivity.class); }
|
測試元件初始化
1 2 3 4 5 6 7 8 9
| @Override protected void setUp() throws Exception { super.setUp();
mMainActivity = (MainActivity) getActivity(); mTestButton = (Button) mMainActivity.findViewById(R.id.test_bt); mEditText = (EditText) mMainActivity.findViewById(R.id.enter); mTextView = (TextView) mMainActivity.findViewById(R.id.show_text); }
|
元件初始化測試
1 2 3 4 5 6
| public void testPreConditions(){ assertNotNull(mMainActivity); assertNotNull(mTestButton); assertNotNull(mEditText); assertNotNull(mTextView); }
|
Step 3: 測試預設值
1 2 3 4 5
| @UiThreadTest public void testInitialization() { assertEquals("", mEditText.getText().toString()); assertEquals("Enter..", mTextView.getText().toString()); }
|
由於在 res/layout/activity_main.xml 中 EditText 和 TextView 的初始設定為
activity_main.xml1 2 3 4 5 6 7 8 9 10 11 12 13 14
| <EditText android:id="@+id/enter" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_centerInParent="true" />
<TextView android:id="@+id/show_text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@id/enter" android:text="Enter..." android:layout_centerHorizontal="true"/>
|
所以測試項 assertEquals(“Enter..”, targetText); 會無法通過測試 (少了一個點號)
錯誤訊息如下
Step 4: 測試未點擊 Test Button 的情況
1 2 3 4 5 6 7
| @UiThreadTest public void testNotChanged() { mEditText.setText("Not Click Test Button");
assertEquals("Not Click Test Button", mEditText.getText().toString()); assertNotSame(mEditText.getText().toString(), mTextView.getText().toString()); }
|
雖然EditText內容以被更改, 但還未點擊 Test Button 時, TextView 的內容不會被更改,
所以測試項目 assertEquals(sourceText, targetText) 會無法通過測試.
錯誤訊息如下
Step 5: 測試點擊 Test Button 的情況
1 2 3 4 5 6 7 8 9
| @UiThreadTest public void testShowText() { mEditText.setText("Click Test Button"); mTestButton.performClick();
assertEquals("Click Test Button", mEditText.getText().toString()); assertEquals("Click Test Button", mTextView.getText().toString()); assertEquals(mEditText.getText().toString(), mTextView.getText().toString()); }
|
點擊 Test Button後, TextView 的內容會更改為EditText內容
所以此測試項為 Pass
Step 6: 再度測試內容
1 2 3 4
| @UiThreadTest public void testTestAgain() { testInitialization(); }
|
若將此測試項移至ActivityUnitTestCase 是可被測試通過的.
因為ActivityUnitTestCase的會重複執行 setUp() 與 tearDown().
所以EditText和TextView都被初始化了.
但是在SingleActivityTestCase 並不會再度執行setUp() 與 tearDown().
EditText和TextView的內容依舊為 “Click Test Button”
所以此測試項無法通過測試.
先前我們有提到 @UiThreadTest 的順序會根據命名來決定順序, 若將此測試項名稱改為
1 2 3 4
| @UiThreadTest public void testInitializationAgain() { testInitialization(); }
|
是可以通過測試的, 所以在命名上要小心.
Source Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
| public class MainActivityTest_Single_Launch extends SingleLaunchActivityTestCase {
MainActivity mMainActivity;
private Button mTestButton; private EditText mEditText; private TextView mTextView;
public MainActivityTest_Single_Launch() { super("com.projects.nick", MainActivity.class); }
@Override protected void setUp() throws Exception { super.setUp();
mMainActivity = (MainActivity) getActivity(); mTestButton = (Button) mMainActivity.findViewById(R.id.test_bt); mEditText = (EditText) mMainActivity.findViewById(R.id.enter); mTextView = (TextView) mMainActivity.findViewById(R.id.show_text); }
public void testPreConditions(){ assertNotNull(mMainActivity); assertNotNull(mTestButton); assertNotNull(mEditText); assertNotNull(mTextView); }
@UiThreadTest public void testInitialization() { assertEquals("", mEditText.getText().toString()); assertEquals("Enter...", mTextView.getText().toString()); }
@UiThreadTest public void testNotChanged() { mEditText.setText("Not Click Test Button");
assertEquals("Not Click Test Button", mEditText.getText().toString()); assertNotSame(mEditText.getText().toString(), mTextView.getText().toString()); }
@UiThreadTest public void testShowText() { mEditText.setText("Click Test Button"); mTestButton.performClick();
assertEquals("Click Test Button", mEditText.getText().toString()); assertEquals("Click Test Button", mTextView.getText().toString()); assertEquals(mEditText.getText().toString(), mTextView.getText().toString()); }
@UiThreadTest public void testTestAgain() { testInitialization(); }
@Override protected void tearDown() throws Exception { super.tearDown(); } }
|