敏捷實(shí)踐 (1) - 我們是如何自動化App驗(yàn)收標(biāo)準(zhǔn)

1. 問題背景

Scrum敏捷過程對交付質(zhì)量有著嚴(yán)格的要求:零缺陷的增量發(fā)布剂买。

要做到這一點(diǎn)意味著每個迭代發(fā)布都必須對 AC (Acceptance Criteria - 驗(yàn)收標(biāo)準(zhǔn)) 進(jìn)行全回歸胶滋,隨著迭代中增量交付的增加,全回歸的工作量與所需的時間也隨之增加筹陵。

我們在做APP開發(fā)過程中闷游,app開發(fā)人員 告訴我這app自動化測試搞不了惊奇,測試人員 也說,不好搞开仰,很麻煩拟枚,而且還得靠錄屏,blablabla.......

結(jié)果測試工作往往只能依賴人手進(jìn)行測試众弓,AC要靠人手來全回歸測試恩溅,就會發(fā)生這樣一種情景:

通常一個迭代的周期為兩周10個工作日。

  • 迭代1谓娃, 計劃完成5個功能脚乡,相應(yīng)的AC也就不多,如果1天就能全部回歸滨达,那么開發(fā)有9天時間來實(shí)現(xiàn)功能奶稠。
  • 迭代2, 計劃完成4個功能弦悉,相應(yīng)的AC加上迭代1的AC窒典,需要2天才能全部回歸,那么開發(fā)有8天的時間來實(shí)現(xiàn)功能稽莉。
  • 迭代3瀑志,計劃完成3個功能,相應(yīng)的AC加上兩個迭代的AC污秆,可能需要3天才能全部回歸劈猪,那么開發(fā)有7天的時間來實(shí)現(xiàn)功能。
  • ...

每次迭代AC全回歸的所需的時間在不斷增加良拼,而能用于開發(fā)的時間不斷在受到擠壓而減少战得,能交付的功能也就不斷在減少。

  • 要質(zhì)量就沒速度庸推,如此還能敏捷的起來嗎常侦?
  • 不少團(tuán)隊(包括我們)采用了犧牲交付質(zhì)量(僅部分回歸甚至無回歸)來確保開發(fā)進(jìn)度浇冰,這樣做既不符合敏捷過程的價值觀,實(shí)際上也沒有達(dá)到交付目標(biāo)聋亡。
  • 還有一個土豪的做法肘习,就是增配測試。

我們一直在探索這個問題的解決方案坡倔,既想確保增量發(fā)布的速度漂佩,又想擁有交付質(zhì)量。只能想辦法把AC自動化起來罪塔,全回歸就不需要占用太多人手投蝉,而且還能隨時進(jìn)行,所需要的時間也大大縮短征堪。


2. 解決方案

在2017年1月份的ScrumMaster培訓(xùn)課中瘩缆,聊起App自動化測試有什么工具,便有小伙伴提了一下Appium请契】劝瘢回來后便查資料研究,發(fā)現(xiàn)有兩個非常不錯的自動化工具爽锥,一個就是Appium涌韩,另一個是阿里系的Macaca。這里不得不說氯夷,Macaca做的很不錯臣樱,javascript寫測試也相對容易上手。

然而腮考,做了對比后雇毫,我決定還是選用Appium。原因很簡單踩蔚,Appium支持Ruby和Cucumber棚放,我們的后端正好是用RubyOnRails寫的,后端開發(fā)人員已經(jīng)在寫后端過程中積累了許多編寫自動化測試用例的經(jīng)驗(yàn)馅闽。正好也可以來寫app的自動化測試飘蚯。


2.1 環(huán)境準(zhǔn)備

以下內(nèi)容的運(yùn)行環(huán)境為 MacOS 10.12 + Ruby 2.3.3 + NodeJS 7.x。
至于如何安裝 Ruby 和 NodeJS福也,這個應(yīng)當(dāng)為基本技能局骤,請自行搞定。

請不要問我如何在Windows上去搭建環(huán)境的有關(guān)問題暴凑,我只會建議要么白蘋果峦甩,要么黑蘋果,要么Ubuntu (不支持iOS)现喳。要么走您凯傲。

由于npmjs.org rubygems.org都在國外犬辰,訪問速度慢且不穩(wěn)定,建議先搭好梯子泣洞,或者改用國內(nèi)的源忧风。


2.1.1 Appium 1.6.3 安裝

npm install -g appium
npm install -g appium-doctor
# ios還需要安裝兩個工具 ios-deploy 用于安裝app到真機(jī);Carthage 用于安裝app到模擬器
brew install carthage
brew install ios-deploy
# brew 是個什么鬼球凰,如何安裝的?沒什么技術(shù)含量腿宰,請自行baidu

# 完成后可以運(yùn)行appium-doctor診斷一下環(huán)境是否正常
# 如果沒有android需求的呕诉,可以不用管 JAVA_HOME 與 android adb 等錯誤
appium-doctor

一切正常會得到類似這個信息


appium-doctor-screenshot.png

2.1.2 安裝 Appium 的 Ruby 驅(qū)動,和appium ruby console

gem install appium_lib
gem install appium_console

至此吃度,環(huán)境準(zhǔn)備工作已經(jīng)完成甩挫。


2.2 編寫自動化測試用例

測試用例采用Cucumber方式編寫,F(xiàn)eature 對應(yīng) 用戶故事椿每,Scenario 對應(yīng) AC伊者。
一個Feature包含多個Scenarios。
一個用戶故事有多個 AC驗(yàn)收標(biāo)準(zhǔn)间护。

至于Cucumber, 有空我會再寫一個文章亦渗。目前請先自行baidu之。


2.2.1 創(chuàng)建目錄

mkdir app_test
cd app_test
# 創(chuàng)建測試用例目錄
mkdir features 
# 創(chuàng)建測試用例步驟目錄
mkdir features/steps
# 創(chuàng)建支持目錄
mkdir features/support

2.2.2 準(zhǔn)備Ruby Cucumber的Gemfile

$ cat Gemfile

source 'https://gems.ruby-china.org'

gem 'appium_lib',         '~> 9.3.0'
gem 'rest-client',        '~> 1.6.7'
gem 'rspec',              '~> 2.14.1'
gem 'cucumber',           '~> 1.3.15'
gem 'rspec-expectations', '~> 2.14.5'
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包

bundle install

2.2.3 cucumber env

$ cat features/support/env.rb

# This file provides setup and common functionality across all features.  It's
# included first before every test run, and the methods provided here can be 
# used in any of the step definitions used in a test.  This is a great place to
# put shared data like the location of your app, the capabilities you want to
# test with, and the setup of selenium.

require 'rspec/expectations'
require 'appium_lib'
require 'cucumber/ast'
require 'sauce_whisk'

# 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('./', __FILE__), verbose: true

Appium::Driver.new(caps)
Appium.promote_appium_methods AppiumWorld

World do
  AppiumWorld.new
end

# 結(jié)束時汁尺,推出驅(qū)動
at_exit { $driver.driver_quit }

# 在運(yùn)行標(biāo)有@reset_driver的Scenario前重啟驅(qū)動
Before("@reset_driver") do
  $driver.restart
end

2.2.4 appium配置文件 appium.txt

關(guān)于appium.txt配置說明可以參考文檔 appium-server-capabilities

$ cat features/support/appium.txt

[caps]
platformName = "ios"
deviceName = "iPhone 6s"
platformVersion = "10.2"
app = '../ios/build/Build/Products/Debug-iphonesimulator/PuKe.app'
automationName = 'XCUITest'
language = 'zh'
locale = 'zh_CN'

[appium_lib]
sauce_username = false
sauce_access_key = false

2.3 編寫測試用例

每一用戶故事的測試用例編寫為一個feature法精。


2.3.1 編寫郵箱登陸用戶故事的AC

郵箱登陸用戶故事只是登陸故事中的其中一個, 故事ID US004

$cat features/US004_login_by_email.feature

Feature: US_004 郵箱登錄
  為了正常使用需要登錄身份的功能
  作為一個已經(jīng)用郵箱注冊過的用戶
  我想要用郵箱和密碼登錄系統(tǒng)

  @reset_driver
  Scenario: AC_US004_02 登錄錯誤: 正確郵箱+錯誤密碼登錄
    Given 我已經(jīng)用郵箱 test_user@mytest.com 與密碼 test123 注冊過賬號
    When 我在 "主頁面" 點(diǎn)擊 "登錄/注冊" 進(jìn)入 "登錄頁面"
    And 我在 "郵箱或手機(jī)" 輸入 "test_user@mytest.com"
    And 我在 "密碼" 輸入 "b123456"
    And 我按下按鈕 "登錄"
    Then 我應(yīng)當(dāng)看到浮動提示 "用戶密碼不匹配"

  Scenario: AC_US004_03 登錄錯誤: 沒有輸入用戶名和密碼
    Given 我已經(jīng)用郵箱 test_user@mytest.com 與密碼 test123 注冊過賬號
    And 我在 "郵箱或手機(jī)" 輸入 ""
    When 我在 "密碼" 輸入 ""
    And 我按下按鈕 "登錄"
    Then 我應(yīng)當(dāng)看到浮動提示 "請?zhí)顚懲暾?

  Scenario: AC_US004_04 登錄錯誤: 輸入用戶名沒有輸入密碼
    Given 我已經(jīng)用郵箱 test_user@mytest.com 與密碼 test123 注冊過賬號
    And 我在 "郵箱或手機(jī)" 輸入 "test_user@mytest.com"
    And 我在 "密碼" 輸入 ""
    When 我按下按鈕 "登錄"
    Then 我應(yīng)當(dāng)看到浮動提示 "請?zhí)顚懲暾?

  Scenario: AC_US004_01 正常郵箱+密碼登錄
    Given 我已經(jīng)用郵箱 test_user@mytest.com 與密碼 test123 注冊過賬號
    When 我在 "郵箱或手機(jī)" 輸入 "test_user@mytest.com"
    And 我在 "密碼" 輸入 "test123"
    And 我按下按鈕 "登錄"
    Then 我應(yīng)當(dāng)?shù)竭_(dá) "主頁面"
    And 等待 2 秒后退出


2.3.2 為feature編寫相應(yīng)的steps

Scenario 中的每個 Given When Then And 都在steps.rb 中有對應(yīng)的定義。

$ cat features/step_definitions/steps.rb

# These are the 'step definitions' which Cucumber uses to implement features.
#
# Each step starts with a regular expression matching the step you write in
# your feature description.  Any variables are parsed out and passed to the
# step block.
#
# The instructions in the step are then executed with those variables.
#
# In this example, we're using rspec's assertions to test that things are happening,
# but you can use any ruby code you want in the steps.
#
# The '$driver' object is the appium_lib driver, set up in the cucumber/support/env.rb
# file, which is a convenient place to put it as we're likely to use it often.
# This is a different use to most of the examples;  Cucumber steps are instances
# of `Object`, and extending Object with Appium methods (through 
# `promote_appium_methods`) is a bad idea.
#
# For more on step definitions, check out the documentation at
# https://github.com/cucumber/cucumber/wiki/Step-Definitions
#
# For more on rspec assertions, check out
# https://www.relishapp.com/rspec/rspec-expectations/docs

Given(/^我已經(jīng)用郵箱 (.*) 與密碼 (.*) 注冊過賬號$/) do |email, password|
  # sleep(1)
  puts "DEBUG: email: #{email}"
  puts "DEBUG: password: #{password}"
end

When(/^我在 "主頁面" 點(diǎn)擊 "登錄\/注冊" 進(jìn)入 "登錄頁面"$/) do
  # 等待主頁面就緒, 主頁面ID 為 home_page
  wait { id('home_page') }
  # 點(diǎn)擊 主頁面中的 '登錄/注冊' 按鈕痴突,按鈕ID為 btn_to_login
  id('btn_to_login').click

  # 檢查頁面跳轉(zhuǎn)到 登錄頁面搂蜓, 登錄頁面ID為 page_login_account
  wait { id('page_login_account') }
end

When(/^我在 "(.*?)" 輸入 "(.*?)"$/) do |input_field, input_value|
  input_id = case input_field
               when '郵箱或手機(jī)'
                 'input_username'
               when '密碼'
                 'input_password'
               else
                 'unknown'
             end
  input_box = id(input_id)           # 定位指定的輸入框
  input_box.clear                    # 清除原來的內(nèi)容
  input_box.type "#{input_value}\n"  # 輸入新內(nèi)容并回車
end

And(/^我按下按鈕 "登錄"$/) do
  id('btn_login').click
end

Then(/^我應(yīng)當(dāng)看到浮動提示 "(.+)"$/) do |msg|
  msg.strip!
  puts "DEBUG: 期待 #{msg}"
  wait { find(msg) }
end

Then(/^我應(yīng)當(dāng)?shù)竭_(dá) "主頁面"$/) do
  wait { id('home_page') }
end

And(/^等待 (\d+) 秒后.*/) do |seconds|
  sleep(seconds.to_i)
end


3. 運(yùn)行測試用例

3.1 運(yùn)行 Appium

運(yùn)行測試用例前必須先啟動appium,
新打開一個命令行窗口
$ appium

run_appium.png

3.2 運(yùn)行測試用例

在 test_app 目錄中

$ cucumber features/US004_login_by_email.feature

run_cucumber_feature.png

3.3 觀看測試用例的運(yùn)行錄屏

http://v.youku.com/v_show/id_XMjUyMTkwODUzMg==.html


3.4 示例代碼參考

https://github.com/appium/sample-code/


4. 總結(jié)

拋開復(fù)雜的appium、cucumber steps辽装,發(fā)現(xiàn)沒帮碰,測試用例是不是很容易理解?

  Scenario: AC_US004_01 正常郵箱+密碼登錄
    Given 我已經(jīng)用郵箱 test_user@mytest.com 與密碼 test123 注冊過賬號
    When 我在 "郵箱或手機(jī)" 輸入 "test_user@mytest.com"
    And 我在 "密碼" 輸入 "test123"
    And 我按下按鈕 "登錄"
    Then 我應(yīng)當(dāng)?shù)竭_(dá) "主頁面"
    And 等待 2 秒后退出

像上面的AC拾积,就算是非技術(shù)人員也能分分鐘寫出來殉挽,我們的產(chǎn)品經(jīng)理、UI設(shè)計師都在參與編寫AC殷勘,這就是我們選擇cucumber ruby的根本原因此再。

本來打算一篇寫完的,寫著寫著玲销,發(fā)現(xiàn)要寫的內(nèi)容太多了输拇,決定還是寫成一個系列:

  • 首先、用Appium來測試贤斜,也存在一些坑要填策吠。
  • 上面的feature和steps逛裤,為了演示好理解,做了相當(dāng)?shù)暮喕锬ā?shí)際上带族,我們的steps經(jīng)過一些重構(gòu),變得很通用靈活蟀给,后續(xù)放出來蝙砌。
  • Appium的配置與基本指令
  • 輔助神器 Appium Ruby Console (ARC) 的使用
  • 如何用Cucumber編寫自動化測試
  • React-Native類型的APP自動化有哪些坑需要繞過

有空的時候再接著寫 (二)、(三)跋理。择克。。前普。肚邢。。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末拭卿,一起剝皮案震驚了整個濱河市骡湖,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌峻厚,老刑警劉巖响蕴,帶你破解...
    沈念sama閱讀 217,542評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異目木,居然都是意外死亡换途,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評論 3 394
  • 文/潘曉璐 我一進(jìn)店門刽射,熙熙樓的掌柜王于貴愁眉苦臉地迎上來军拟,“玉大人,你說我怎么就攤上這事誓禁⌒赶ⅲ” “怎么了?”我有些...
    開封第一講書人閱讀 163,912評論 0 354
  • 文/不壞的土叔 我叫張陵摹恰,是天一觀的道長辫继。 經(jīng)常有香客問我,道長俗慈,這世上最難降的妖魔是什么姑宽? 我笑而不...
    開封第一講書人閱讀 58,449評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮闺阱,結(jié)果婚禮上炮车,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好瘦穆,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,500評論 6 392
  • 文/花漫 我一把揭開白布纪隙。 她就那樣靜靜地躺著,像睡著了一般扛或。 火紅的嫁衣襯著肌膚如雪绵咱。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,370評論 1 302
  • 那天熙兔,我揣著相機(jī)與錄音悲伶,去河邊找鬼。 笑死黔姜,一個胖子當(dāng)著我的面吹牛拢切,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播秆吵,決...
    沈念sama閱讀 40,193評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼五慈!你這毒婦竟也來了纳寂?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,074評論 0 276
  • 序言:老撾萬榮一對情侶失蹤泻拦,失蹤者是張志新(化名)和其女友劉穎毙芜,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體争拐,經(jīng)...
    沈念sama閱讀 45,505評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡腋粥,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,722評論 3 335
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了架曹。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片隘冲。...
    茶點(diǎn)故事閱讀 39,841評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖绑雄,靈堂內(nèi)的尸體忽然破棺而出展辞,到底是詐尸還是另有隱情,我是刑警寧澤万牺,帶...
    沈念sama閱讀 35,569評論 5 345
  • 正文 年R本政府宣布罗珍,位于F島的核電站,受9級特大地震影響脚粟,放射性物質(zhì)發(fā)生泄漏覆旱。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,168評論 3 328
  • 文/蒙蒙 一核无、第九天 我趴在偏房一處隱蔽的房頂上張望扣唱。 院中可真熱鬧,春花似錦、人聲如沸画舌。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,783評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽曲聂。三九已至霹购,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間朋腋,已是汗流浹背齐疙。 一陣腳步聲響...
    開封第一講書人閱讀 32,918評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留旭咽,地道東北人贞奋。 一個月前我還...
    沈念sama閱讀 47,962評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像穷绵,于是被迫代替她去往敵國和親轿塔。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,781評論 2 354

推薦閱讀更多精彩內(nèi)容