從 0 到 1 搭建移動 App 功能自動化測試平台 (4):自動化測試代碼?工程化?
在本系列的上一篇文章中,我通過系統登錄這一典型功能點,演示了編寫自動化測試腳本的整個流程,並對測試腳本進行了初步優化。
在本文中,我將重點介紹如何對自動化測試腳本實現?工程化?的組織和管理。
測試腳本?工程化?
首先說下什麼是測試腳本的工程化。
通過之前的工作,我們已經可以讓單個自動化測試用例正常運行起來了。然而,這還只算是一個demo,一切才剛剛開始。
試想,一個項目的自動化測試用例少則數百,多則成千上萬。如何將這些自動化測試用例組織起來?如何實現更好的可重用機制?如何實現更好的可拓展機制?這些都還是我們當前的demo所不具備的,也是我們需要通過「工程化」手段進行改造的原因。
引入Minitest/RSpec
在Ruby中,說到測試首先就會想到Minitest或RSpec,這是Ruby中用的最多的兩個測試框架。通過這些框架,我們可以很好地實現對Ruby測試用例的管理。
同樣地,由於我們的自動化測試腳本是採用Ruby編寫的,因此我們也可以使用Minitest/RSpec來管理我們的自動化測試用例。
基於該想法,我們採用RSpec對之前的系統登錄測試用例進行工程結構初始化。對於熟悉Ruby編程,或者有一定代碼基礎的同學而言,很自然地,可以將測試用例框架初始化為如下結構。
├── Gemfilen├── androidn│ └── appium.txtn├── commonn│ ├── requires.rbn│ └── spec_helper.rbn└── iosn ├── appium.txtn └── specn └── login_spec.rbn
在Gemfile中,指定了項目依賴的庫。
# filename: Gemfilensource https://gems.ruby-china.orgnngem rspecngem appium_libngem appium_consolen
在common/spec_helper.rb中,定義了模擬器和RSpec初始化相關的代碼。
# filename: common/spec_helper.rbnndef setup_drivern return if $drivern appium_txt = File.join(Dir.pwd, ios, appium.txt)n caps = Appium.load_appium_txt file: appium_txtn Appium::Driver.new capsnendnndef promote_methodsn Appium.promote_appium_methods RSpec::Core::ExampleGroupnendnnsetup_drivernpromote_methodsnnRSpec.configure do |config|nn config.before(:each) don $driver.start_drivern wait { alert_accept }n endnn config.after(:each) don driver_quitn endnnendn
在common/requires.rb中,實現了對相關庫文件的引用。
# filename: common/requires.rbnn# load libnrequire rspecnrequire appium_libnn# setup rspecnrequire_relative spec_helpern
在ios/appium.txt中,對iOS模擬器信息和測試包路徑進行了配置。
[caps]nplatformName = "ios"ndeviceName = "iPhone 6s"nplatformVersion = "9.3"napp = "/Users/Leo/MyProjects/AppiumBooster/ios/app/test.app"n
在ios/spec/目錄中,則是測試用例的內容。例如,ios/spec/login_spec.rb對應的就是系統登錄的測試用例。
# filename: ios/spec/login_spec.rbnrequire_relative ../../common/requiresnndescribe Login donn it with valid account don wait { id(btnMenuMyAccount).click }n wait { id uiviewMyAccount }nn wait { id(tablecellMyAccountLogin).click }n wait { id uiviewLogIn }nn wait { id(txtfieldEmailAddress).type leo.lee@dji.com }n wait { id(sectxtfieldPassword).type 123321 }n wait { id(btnLogin).click }n wait { id tablecellMyMessage }n endnnendn
通過以上代碼結構初始化,我們的測試用例框架的雛形就形成了。接下來,在Terminal中切換到項目根目錄,然後通過rspec ios命令就可以執行ios目錄中的測試用例了。
? rspec iosn.nnFinished in 2 minutes 7.2 seconds (files took 1.76 seconds to load)n1 example, 0 failuresn
完整的代碼請參考debugtalk/AppiumBooster的1.FirstTest分支。
添加第二條測試用例
現在,我們嘗試往當前的測試框架中添加第二條測試用例。
例如,第二條測試用例要實現啟動後從當前地區切換至中國。那麼,就可以新增ios/spec/change_country_spec.rb。
# filename: ios/spec/change_country_spec.rbnrequire_relative ../../common/requiresnndescribe Change country donn it from Hong Kong to China don wait { id(btnMenuMyAccount).click }n wait { id uiviewMyAccount }nn wait { id(tablecellMyAccountSystemSettings).click }n wait { id txtCountryDistrict }nn wait { id(txtCountryDistrict).click }n wait { id uiviewSelectCountry }nn wait { id(tablecellSelectCN).click }nn wait { id(btnArrowLeft).click }n wait { id uiviewMyAccount }n endnnendn
完整的代碼請參考debugtalk/AppiumBooster的2.SecondTest分支。
現在我們凝視已經添加的兩個測試用例,有發現什麼問題么?
是的,重複代碼太多。在每一步操作中,都要用id來定位控制項,還要用wait來實現等待機制。
除此之外,當前代碼最大的問題就是測試用例與控制項映射雜糅在一起。造成的後果就是,不管是控制項映射發生變動,還是測試用例需要修改,都要來修改這一份代碼,維護難度較大。
重構:測試用例與控制項映射分離
基於以上問題,我們首要的改造任務就是將測試用例與控制項映射進行分離。
考慮到常用的控制項操作方法就只有幾個(click,type),因此我們可以將控制項操作方法單獨封裝為一個模塊,作為公共模塊。
module Actionsnn def clickn wait { @found_cell.click }n endnn def type(text)n wait { @found_cell.type text }n endnnendn
然後,將APP中每一個頁面封裝為一個模塊(module),將頁面中的控制項映射為模塊的靜態方法(method),並通過include機制引入方法模塊。
例如,登錄頁面就可以封裝為如下代碼。
module Pagesn module Loginn class << selfnn include Actionsnn def field_Email_Addressn @found_cell = wait { id txtfieldEmailAddress }n selfn endnn def field_Passwordn @found_cell = wait { id sectxtfieldPassword }n selfn endnn def button_Loginn @found_cell = wait { id btnLogin }n selfn endnn endn endnendnnmodule Kerneln def loginn Pages::Loginn endnendn
這裡還用到了一點Ruby元編程技巧,就是將頁面模塊封裝為一個方法,並加入到Kernel模塊下。這樣做的好處就是,我們可以在項目的任意地方直接通過login.button_Login.click這樣的形式來對控制項進行操作了。
完成以上改造後,系統登錄測試用例就可以採用如下形式進行編寫了。
describe Login donn it with valid account don # switch to My Account pagen my_account.button_My_Account.clickn inner_screen.has_control uiviewMyAccountnn # enter login pagen my_account.button_Login.clickn inner_screen.has_control uiviewLogInnn # loginn login.field_Email_Address.type leo.lee@dji.comn login.field_Password.type 123321n login.button_Login.clickn inner_screen.has_control tablecellMyMessagen endnnendn
完整的代碼請參考debugtalk/AppiumBooster的3.RefactorV1分支。
To be continued ...
經過這一輪重構,我們的測試用例與控制項映射已經實現了分離,測試用例的可重用性與可擴展性也得到了極大的提升。
然而,在當前模式下,所有的測試用例仍然是以代碼形式存在的,新增和修改測試用例時都需要到工程目錄下編輯Ruby文件。
那有沒有一種可能,我們只需要在表格中維護自動化測試用例(如下圖),然後由代碼來讀取表格內容就可以自動執行測試呢?
是的,這就是我們對測試框架進行?工程化?改造的下一個形態,也就是AppiumBooster現在的樣子。
在下一篇文章中,我們再進行詳細探討。
Read More ...
微信公眾號:DebugTalk
原文鏈接:http://debugtalk.com/post/build-app-automated-test-platform-from-0-to-1-refactor-testcase-scripts/《從0到1搭建移動App功能自動化測試平台》系列:http://debugtalk.com/tags/F0T1/推薦閱讀:
※如果想在GitHub上掛一個自己的開源程序,應該如何上手開始準備?
※打算做一個獨立網站,有人可以幫忙解釋一下外包建站、開源程序建站以及SaaS建站嗎?
※那些年我使用過的開源程序
※深入淺出開源性能測試工具Locust(使用篇1)
※打造心目中理想的自動化測試框架 (AppiumBooster)