從 UI 元件上測試你的 App

謀智台客之前的文章提到了有關 Gaia-ui-test ,在 Mozilla 工作團隊的努力下,這套工具已經越來越健全,足以寫出貼近使用者體驗的測試了。 對於開發者來說,更重要的是如何使用它來幫助自己開發的程式。下面以 Contact App 的例子,如何透過 Gaia-ui-test 的架構來測試 App 。所有的範例都可以從 Github 上查看原始碼。

安裝 client

Gaia ui Test 使用之前必須確認手機有安裝 Marionette Server ,建置時選用開發者模式即有內建。由於整個專案以及相依的套件都存到 pypi 上面,一個指令就可以完成安裝。目前 Server 上的版本 ,可以依照手機上的 Firefox OS 版本來安裝。最新版本可透過

easy_install gaia-ui-test

使用 B2G Desktop build

這篇是 MDN 上有關 B2G Desktop 的中文介紹。用 B2G Desktop 來執行 gaia-ui-test 相當簡單:

gaiatest --binary={Firefox os 執行檔} {想執行的 test case/manifest}

測項的正確性與程式本身重要性不分軒輊,在實際到手機上進行測試之前,必須反覆確保在 Desktop 版本執行成功。

跑在 Firefox Phone 之上

執行在手機的差別只在於必須把手機上的 port 導到本機端,再用本機端的 test runner 傳送指令並控制行為。可透過下面指令:

adb forward tcp:2828 tcp:2828

port 2828 可以選用不同的號碼。執行只要下

gaiatest --address=localhost:2828 --testvars={測試設置項目} {想執行的 test case/manifest}

測試 Contact App

下面以 Contact App 做例子介紹測項的撰寫。 Contact App 在 2.0 版本重新設計視覺的部分,但由於主要的 html element 變動不大,原本的測項可以沿用。測項之中有些是 python ,也可以用 javascript ,使用方法大同小異。 先來看看 test_add_new_contact.py 裡的:

from gaiatest import GaiaTestCase

from gaiatest.mocks.mock_contact import MockContact
from gaiatest.apps.contacts.app import Contacts

class TestContacts(GaiaTestCase):

def test_add_new_contact(self):
"""https://moztrap.mozilla.org/manage/case/1309/"""

    self.contact = MockContact()

    contacts_app = Contacts(self.marionette)
    contacts_app.launch()

    new_contact_form = contacts_app.tap_new_contact()

    # Enter data into fields
    new_contact_form.type_given_name(self.contact['givenName'])
    new_contact_form.type_family_name(self.contact['familyName'])

    new_contact_form.type_phone(self.contact['tel']['value'])
    new_contact_form.type_email(self.contact['email']['value'])
    new_contact_form.type_street(self.contact['adr']['streetAddress'])
    new_contact_form.type_zip_code(self.contact['adr']['postalCode'])
    new_contact_form.type_city(self.contact['adr']['locality'])
    new_contact_form.type_country(self.contact['adr']['countryName'])
    new_contact_form.type_comment(self.contact['note'])

    new_contact_form.tap_done()
    self.wait_for_condition(lambda m: len(contacts_app.contacts) == 1)

    self.assertEqual(contacts_app.contacts[0].name, self.contact['givenName'])

測試檔案需要有一個主要 class 繼承自 GaiaTestCase ,所有 member function 帶 test_ 字首皆會被當作一個測項。MockContact 裡面存放測試資料,至於如何使用 Contact App 就透過 import 的 Contact ,操作它的 member function 來達成。13行以下,先創建 Contact ,透過 launch() 來啟動 contact , tap_new_contact() 讓程式按下建立新聯絡人按鈕。接下來在每一個聯絡人欄位裡填入資料,然後按下 done 完成。 測試步驟結束之後,先用 wait_for_condition 確定聯絡人已經可以看得見,再透過 assertEqual 比對 givenName 跟預設的內容是否相同。根據測試的複雜度可能需要多個檢查,任何一個檢查失敗都會讓測試終止並且被標記為失敗。 那關於 App 的操作,難道沒有使用說明書嗎?當然有,先參考: https://github.com/mozilla-b2g/gaia/blob/master/tests/python/gaia-ui-tes...

_new_contact_button_locator = (By.ID, 'add-contact-button')
_settings_button_locator = (By.ID, 'settings-button')
_favorites_list_locator = (By.ID, 'contacts-list-favorites')
_select_all_wrapper_locator = (By.ID, 'select-all-wrapper')
_select_all_button_locator = (By.CSS_SELECTOR, 'button[data-l10n-id="selectAll"]')
_export_button_locator = (By.ID, 'select-action')
_status_message_locator = (By.ID, 'statusMsg')

這裡定義了操作元件的『位置』。 Marionette client 定義了幾種可以搜尋位置的方式,By.ID , By.CLASS_NAME ,或者是 By.CSS_SELECTOR ,可以參考 這裡

def tap_new_contact(self):
    self.marionette.find_element(*self._new_contact_button_locator).tap()
    from gaiatest.apps.contacts.regions.contact_form import NewContact
    new_contact = NewContact(self.marionette)
    new_contact.wait_for_new_contact_form_to_load()
    return new_contact

這個函式定義如何找到新增聯絡人按鍵並且使用。 附上實際執行的影片。

總結

* 在 Firefox OS 上做測試最好的選擇是透過 Gaia-ui-test,有整合且有效率的方式使用鍵盤與一些系統功能。 * 當測試一個新的 App 時,例如文中提到的 Contact App ,可以先構築一個 Test App Module 以定義各種功能,再從使用者觀點來進行測項的撰寫。類似的整合性測試可以幫助開發者反覆確認使用者行為以及功能改變所帶來的衝擊。

想法?

測試的困難或者意見歡迎丟到 pyang@mozilla.com ,或者在 Mozilla irc 上面找到 pyang