前言
前面介紹了Appium的環(huán)境配置和元素定位技巧,一些就緒后,馬上開始單元測(cè)試用例的編寫吧,下面手把手教你編寫測(cè)試用例
下面例子全部使用Sublime Text編輯器編寫
1、新建文件夾
在合適的位置創(chuàng)建測(cè)試目錄,例子
cd Desktop
mkdir 測(cè)試用例
2、創(chuàng)建Gemfile文件,導(dǎo)入ruby依賴庫(kù)
source 'https://www.rubygems.org'
gem 'appium_lib', '~> 9.7.4'
gem 'rest-client', '~> 2.0.2'
gem 'rspec', '~> 3.6.0'
gem 'cucumber', '~> 2.4.0'
gem 'rspec-expectations', '~> 3.6.0'
gem 'spec', '~> 5.3.4'
gem 'sauce_whisk', '~> 0.0.13'
gem 'test-unit', '~> 2.5.5' # required for bundle exec ruby xunit_android.rb
Gem 是 Ruby 模塊 (叫做 Gems) 的包管理器。其包含包信息,以及用于安裝的文件。
Gem通常是依照".gemspec"文件構(gòu)建的,包含了有關(guān)Gem信息的YAML文件。Ruby代碼也可以直接建立Gem,這種情況下通常利用Rake來進(jìn)行。
3、安裝ruby依賴庫(kù)
在命令行輸入下面命令
bundle install
4、初始化cucumber
cucumber --init
執(zhí)行上面命令,會(huì)生成如下目錄結(jié)構(gòu)
features # 存放feature的目錄
├── step_definitions # 存放steps的目錄
└── support # 環(huán)境配置
└── env.rb
5、新建apps目錄
mkdir apps
將目標(biāo).app文件拖到apps目錄下,注意:這里如果使用模擬器測(cè)試,需要app文件是以模擬器架構(gòu)(eg: iPhone 8)編譯的,如果使用真機(jī)測(cè)試,那么app文件需要使用真機(jī)架構(gòu)編譯(eg: Generic iOS Device)
補(bǔ)充:打開工程,command+U,build完成之后,可在工程的Products目錄下看到app文件
6、設(shè)置Appium服務(wù)器初始化參數(shù)
新建文件appium.txt
使用xcrun simctl list devices查看可用的設(shè)備

設(shè)置Desired Capabilities,例如
[caps]
# 模擬器
platformName = "ios"
deviceName = "iPhone 8"
platformVersion = "11.1"
app = "/Users/yangfangming/Desktop/TuanFund-Appium/apps/TuanFundApp/build/TuandaiFund.app"
automationName = "XCUITest"
參數(shù)描述
| 鍵 | 描述 | 值 |
|---|---|---|
| automationName | 自動(dòng)化測(cè)試的引擎 | 例如 XCUITest、uiautomator2 |
| platformName | 使用的手機(jī)操作系統(tǒng) | 例如 iOS, Android, 或者 FirefoxOS
|
| platformVersion | 手機(jī)操作系統(tǒng)的版本 | 例如 7.1, 4.4 |
| deviceName | 使用的手機(jī)或模擬器類型 | 例如 iPhone 8,Nexus_5X |
| app | 本地絕對(duì)路徑或遠(yuǎn)程 http URL 所指向的一個(gè)安裝包(.ipa,.apk,或 .zip 文件) | /abs/path/to/my.apk 或 http://myapp.com/app.ipa |
7、根據(jù)appium.txt配置的參數(shù),初始化全局的driver對(duì)象
打開env.rb文件,輸入如下代碼
require 'rspec/expectations'
require 'appium_lib'
require 'cucumber/ast'
# Create a custom World class so we don't pollute `Object` with Appium methods
class AppiumWorld
end
# Load the desired configuration from appium.txt, create a driver then
# Add the methods to the world
caps = Appium.load_appium_txt file: File.expand_path('../appium.txt', __FILE__), verbose: true
Appium::Driver.new(caps)
Appium.promote_appium_methods AppiumWorld
World do
AppiumWorld.new
end
Before { $driver.start_driver }
After { $driver.driver_quit }
8、新建feature文件,這里以登錄為例,新建login.feature文件,輸入如下代碼
#language: zh-CN
功能: 賬戶測(cè)試
# 作為一個(gè)開發(fā)者
# 我已經(jīng)注冊(cè)了用戶名為18576771524,密碼為123456a的賬號(hào)
# 我希望能使用這個(gè)賬號(hào)登錄
場(chǎng)景: 驗(yàn)證登錄成功
假如 廣告或者引導(dǎo)頁(yè)面存在,跳過廣告和引導(dǎo)頁(yè)面
當(dāng) 點(diǎn)擊 "我的"
并且 點(diǎn)擊 "登錄/注冊(cè)"
并且 在用戶名輸入框輸入 18576771524
并且 在密碼輸入框輸入 123456 "a"
并且 點(diǎn)擊 "登錄"
并且 等待 3 秒
那么 登錄頁(yè)面應(yīng)該消失
創(chuàng)建login.feature文件后,有個(gè)小技巧,執(zhí)行bundle exec cucumber運(yùn)行測(cè)試用例(確保Appium服務(wù)端端已經(jīng)啟動(dòng)),由于這里還沒有創(chuàng)建steps,會(huì)提示如下信息

9、創(chuàng)建steps,根據(jù)上面的提示創(chuàng)建loginSteps.rb文件
最終目錄結(jié)構(gòu)如下
├── Gemfile # ruby依賴庫(kù)
├── Gemfile.lock # 依賴庫(kù)版本管理
├── apps # 目標(biāo)app
│ └── TuandaiFund.app
└── features # 存放feature、steps的目錄
├── login.feature
├── step_definitions # 存放steps的目錄
│ └── loginSteps.rb
└── support # 環(huán)境配置
├── appium.txt
└── env.rb
編寫steps
假如(/^廣告或者引導(dǎo)頁(yè)面存在,跳過廣告和引導(dǎo)頁(yè)面$/) do
pending # Write code here that turns the phrase above into concrete actions
end
當(dāng)(/^點(diǎn)擊 "([^"]*)"$/) do |arg1|
pending # Write code here that turns the phrase above into concrete actions
end
當(dāng)(/^在用戶名輸入框輸入 (\d+)$/) do |arg1|
pending # Write code here that turns the phrase above into concrete actions
end
當(dāng)(/^在密碼輸入框輸入 (\d+) "([^"]*)"$/) do |arg1, arg2|
pending # Write code here that turns the phrase above into concrete actions
end
當(dāng)(/^等待 (\d+) 秒$/) do |arg1|
pending # Write code here that turns the phrase above into concrete actions
end
那么(/^登錄頁(yè)面應(yīng)該消失$/) do
pending # Write code here that turns the phrase above into concrete actions
end
編寫steps可借助Appium的元素檢查器appium inspector,如何啟動(dòng)inspector,如何定位元素和操作,前面環(huán)境配置和Appium_lib已經(jīng)說過了,這里不再贅述
值得一提的是Gherkin中的關(guān)鍵字,假如、當(dāng)、并且、那么等是等價(jià)的語(yǔ)法糖
假如(/^點(diǎn)擊 "([^"]*)"$/) do
end
當(dāng)(/^點(diǎn)擊 "([^"]*)"$/) do
end
并且(/^點(diǎn)擊 "([^"]*)"$/) do
end
上面3個(gè)steps是等價(jià)的,如果有多個(gè)當(dāng) 點(diǎn)擊 xx 按鈕這樣的feature,只能保留其中一個(gè),否則運(yùn)行測(cè)試用例的時(shí)候會(huì)報(bào)沖突的錯(cuò)誤
編寫完成之后的loginSteps.rb文件如下:
# 跳過廣告頁(yè)面
def dismiss_ad_View
adExist = exists { id("廣告頁(yè)面") }
if adExist
sleep(5)
end
end
# 跳過引導(dǎo)頁(yè)面
def dismiss_guide_page
guideExist = exists { id("引導(dǎo)頁(yè)面") }
# guideExist ? puts("引導(dǎo)頁(yè)面存在") : puts("引導(dǎo)頁(yè)面不存在")
if guideExist
swipe(direction: "left", element: nil)
sleep(1)
swipe(direction: "left", element: nil)
sleep(1)
button("進(jìn)入首頁(yè)").click
sleep(1)
end
end
# 跳過手勢(shì)密碼頁(yè)面
def dismiss_gestrure_password_page
gestureExist = exists { id("手勢(shì)密碼頁(yè)面") }
# guideExist ? puts("引導(dǎo)頁(yè)面存在") : puts("引導(dǎo)頁(yè)面不存在")
if gestureExist
swipe(direction: "right", element: nil)
sleep(1)
swipe(direction: "right", element: nil)
sleep(1)
end
end
假如(/^廣告或者引導(dǎo)頁(yè)面存在,跳過廣告和引導(dǎo)頁(yè)面$/) do
dismiss_ad_View
dismiss_guide_page
dismiss_gestrure_password_page
end
# 按鈕點(diǎn)擊
當(dāng)(/^點(diǎn)擊 "([^"]*)"$/) do |arg1|
e = exists { button(arg1) }
if e
btn = button(arg1)
else
btn = driver.find_element(:id, arg1)
end
wait { btn.click }
end
當(dāng)(/^在用戶名輸入框輸入 (\d+)$/) do |arg1|
textfield("請(qǐng)輸入手機(jī)號(hào)").type arg1
end
當(dāng)(/^在密碼輸入框輸入 (\d+) "([^"]*)"$/) do |arg1, arg2|
textfield("請(qǐng)輸入密碼").type arg1+arg2
end
# 延時(shí)執(zhí)行
當(dāng)(/^等待 (\d+) 秒$/) do |arg1|
sleep(arg1.to_i)
end
那么(/^登錄頁(yè)面應(yīng)該消失$/) do
# 期望:登錄頁(yè)面dismiss
actual = exists { id("登錄頁(yè)面") }
expect(actual).to eq(false)
end
現(xiàn)在進(jìn)入測(cè)試用例目錄運(yùn)行bundle exec cucumber查看測(cè)試效果吧
如果你想使用python來編寫單元測(cè)試,可參考這里