App 測試自動化: RobotFramework + Appium (3)

Steven Shen
Cubo AI
Published in
10 min readJul 2, 2021

這篇要提該如何串接 CI 與 TCMS 系統,基本上想要實踐的想法就是,當開發者將程式碼推上 git 時,觸發 CI pipeline 流程,流程包含 build -> test -> deploy,所以只要有新的版本,都會經過自動化測試的驗證,並且將執行結果更新回到 TCMS 系統上,對 QA 來說,只要關注失敗的 Test Run 就好。

這裡用的 CI 是 gitlab CI,TCMS 是 Kiwi 雲端版。Kiwi 因為有支援 RobotFramework 以及自動化測試,然後又便宜,所以我們公司目前採用 Kiwi 作為 Test Case Management System。

概念其實很簡單,分作兩部分,第一部份怎麼將 RobotFramework 的執行結果更新到 TCMS 系統中,第二部分則是怎麼讓 CI build 同時去觸發 RobotFramework 對新 build 執行自動化測試。

先講第一部分,怎麼將 RF 的執行結果更新到 TCMS 中。

  1. 先安裝 RF 的 kiwitcms 套件 pip install --upgrade kiwitcms-robotframework-plugin
  2. 在 Home directory 中,建立 ~/.tcms.conf 檔案,並輸入你的 Kiwi 網址與帳號密碼
[tcms]
url = https://<your_tenant_name>.tenant.kiwitcms.org/xml-rpc/
username = <login_account>
password = <your_password>

3. 將底下程式 (儲存為 tcmsTools.py)跟你的 RF 腳本放在一起

import os
from zealand.listener import KiwiTCMS
from zealand.listener import RFBackend
class PrivateTenantBackend(RFBackend):
def default_tester_id(self):
user_id = self.built_in.get_variable_value('${build_user_id}')
return user_id
def finish_test_run(self):
self.rpc.TestRun.add_tag(self.run_id, 'automation')
class PrivateTenantKiwi(KiwiTCMS):
backend_class = CuboBackend

為什麼要加這個程式,因為我們的 Kiwi 環境是直接跟 Kiwi 租用的,所以呼叫 tcms_api 的 User api 都會得到 403 Forbidden 的錯誤,為了避開這個錯誤,我在這段程式中多加個 build_user_id 來讓你可以直接輸入 tester 的 user id,而繞開 User API 的呼叫(如果你是自己架設 Kiwi 系統,應該是可以不用多加這段程式碼)。另外,這段程式也會在結束測試時,在該 Test Run 多加個 automation 的 tag,如此一來在 Kiwi 中搜尋 automated test runs 時會比較容易。

接下來在你的 RF 腳本中,要多帶幾個參數

*** Variables ***
${plan_id} 11
${product} Cubo Ai Baby Camera
${build_user_id} 9062
*** Test Cases ****
成功登入
[Tags] TC-1110 login
#.....
  • plan_id: 這個 Test suite 是要測試哪個 Test plan。我的習慣是會建立一個 Automation 的 Test plan,然後在這裡指定該 Test plan 的 ID
  • product: 輸入你 Kiwi 中的產品名稱
  • build_user_id: 輸入 tester 的 user id (如果你不是用我附加的程式碼,請在這裡換成 tester 以及該測試者的 email)

另外在每個 Test case 中,會多帶 [Tags] TC-1110 login ,其中 TC-1110 是某個 test case 的 ID,這裡是用 Tags 的指令來表示該 test case 對應到 Kiwi 中是哪個測試項目。

執行 RobotFramework 的方式改為:

export TCMS_PRODUCT_VERSION=2.0
export TCMS_BUILD=2377
robot --listener tcmsTools.PrivateTenantKiwi tcms_test.robot

執行完畢後,檢查 Kiwi,就會有筆 Test run 被建立出來:

如此一來,RobotFramework 與 Kiwi的串連就完成了。

但是你可能有注意到,上面在執行 RobotFramework 腳本時,有多帶個 TCMS_PRODUCT_VERSION 與 TCMS_BUILD ,這兩個參數從哪裡來,其實就是要從 CI build 而來。

什麼?你們公司還沒有 CI Build? 那要先檢討一下了

我們用 gitlab CI 來做範例,我們的做法是在公司放一台 Mac mini 執行 gitlab-runner 來跑 CI。所以當工程師把 Code commit 並 push 到 gitlab 時就會觸發 CI 流程。

.ios-build-task:
stage: build
tags:
- ios-build
only:
- dev
.ios-test-task:
stage: test
variables:
GIT_SUBMODULE_STRATEGY: recursive
tags:
- ios-build
only:
- dev
stages:
- build
- test
- deploy
variables:
LC_ALL: "en_US.UTF-8"
before_script:
- pod repo update
- pod install
build_project:
extends: .ios-build-task
script:
- xcodebuild clean -workspace "Cubo.xcworkspace" -scheme "Cubo" | xcpretty
- bundle exec fastlane beta_build
artifacts:
paths:
- build.xcarchive
- build
automation-test:
extends: .ios-test-task
script:
- export TCMS_PRODUCT_VERSION=$(bundle exec fastlane run get_version_number target:Cubo | grep Result | grep -oE '[0-9]+\\.[0-9]+\\.?[0-9]*')
- export TCMS_BUILD=$(bundle exec fastlane run get_build_number | grep Result | grep -oE '\\s[0-9]+' | grep -oE '[0-9]+')
- cd automation; robot --listener cubo_tools.CuboKiwi ios_test_cases.robot
deploy:
stage: deploy
script:
- bundle exec fastlane beta_deploy

我們是用 fastlane 來 build app,fastlane 設定如下:

default_platform(:ios)platform :ios do
def install_pods
cocoapods(
clean: true,
podfile: "Podfile",
try_repo_update_on_error: false
)
end
desc "Build app, and archive in ./build.xcarchive path"
lane :beta_build do
install_pods()
xcode_select("/Applications/Xcode.app")
increment_build_number({
build_number: latest_testflight_build_number + 1
})
build_app(workspace: "Cubo.xcworkspace", scheme: "Cubo", archive_path: "./build", output_directory: "./build")
end
desc "Push a new beta build to TestFlight"
lane :beta_deploy do
upload_to_testflight(
skip_waiting_for_build_processing: true
)
end
end

所以可以在 test stage 可以透過 fastlane 取得 app 版本與 build number (build number 是每次會自動遞增)。不過 fastlane 的輸出比較 fancy 會用控制碼帶上顏色,所以在設定給環境變數時,控制碼會造成跟 Kiwi server 溝通上的問題,這問題苦惱了我很久,最後還是寫出這樣很奇怪的處理方式,如果你有更好的解法請務必跟我說:

bundle exec fastlane run get_version_number target:Cubo | grep Result | grep -oE '[0-9]+\\.[0-9]+\\.?[0-9]*'

在 RF 腳本中,你會想要安裝這個剛 build 出來的 app ,你可以指定 app 或者 ipa 的檔案位置,例如在我的 Fastlane 腳本中,我將 app 的 archive 儲存在 build.xcarchive 下,所以在 RF 腳本中 app 可以直接寫死該檔案的絕對路徑,當 RF 腳本執行時,就會安裝這個新 build 出來的版本。

另外這裡有個小 trick,我們的自動化測試腳本是放在另外一個 gitlab repo 中,所以在 iOS repo 裡透過 submodule 的方式,讓 gitlab CI 也自動將另外一個 repo 也 checkout 下來 (automation 目錄下)。

所以當程式碼 push 上 gitlab 時,啟動 gitlab pipeline 會自動完成三個 stage: build, test 以及 deploy

執行完畢後,檢查 Kiwi,一樣會有筆 Test run 被建立出來:

整個設定過程你大概會面臨到很多 try and error 的機會,要設定好也不容易,但盡量是簡化設定,避免環境變動影響到自動化測試的結果,如果自動化測試三天兩頭損壞,那麼久了沒修理就慢慢失去它的意義了。

--

--