1. 程式人生 > >Airtest介紹與指令碼入門

Airtest介紹與指令碼入門

前言

通過閱讀本小節教程,你將瞭解以下內容:

  • 一個Airtest指令碼例子的詳細解析
  • 如何在Python指令碼中呼叫Airtest介面
  • 圖片語句的引數介紹

Airtest介紹

Airtest是一款基於Python的、跨平臺的UI自動化測試框架,基於影象識別原理,適用於遊戲和App。

訪問Github上的 Airtest原始碼地址,可以獲得更多資訊,也歡迎各位幫忙完善專案,提交PR,也可以在issues頁面中 提交bug或建議 。

如何快速上手

首先,想要編寫Airtest指令碼,需要具備基礎的Python語法知識。雖然藉助我們的AirtestIDE提供的錄製功能,也能簡單地根據操作步驟錄製出可以回放操作的指令碼,但是通常來說,熟練掌握Python語法能夠幫助我們寫出應用更廣泛、更不容易出錯的指令碼。

若對 Python 語法不熟悉,網路上有不少非常優秀的Python教程可以學習,例如 廖雪峰的Python新手教程。

關於Airtest專案的安裝、基本使用方法和簡單的例子,請檢視Airtest文件頁的 快速上手 章節。

 一、一個簡單的.air指令碼解析

什麼是.air指令碼

在下載解壓Airtest指令碼的專屬IDE——AirtestIDE後,點選“新建指令碼”按鈕,預設即可建立一個字尾名為`.air`的指令碼檔案,`.air`這是Airtest指令碼的專屬字尾。

讓我們開啟剛才新建指令碼的資料夾,可以看到實際上`.air`指令碼檔案是一個普通的資料夾,裡面附帶了一個同名的`.py`檔案,AirtestIDE在執行指令碼時,實際上執行的是裡面的`.py`檔案。也就是說,Airtest指令碼雖然自帶一個字尾名,然而本質上依然是Python指令碼,遵循的是Python語法,我們可以根據實際需要自由地`import`其他Python第三方庫。

值得注意的是,`.air`資料夾中必須要有同名的`.py`檔案,否則在命令列執行`airtest run test.air` 這樣的執行指令時會導致失敗。

 如何使用AirtestIDE錄製Airtest指令碼

在觀看本篇教程前,如果你已經閱讀過我們的快速上手教程的話,應該就知道我們在錄製指令碼前需要先連上一個裝置。這個裝置可以是一臺Android手機、一個Windows視窗、或是iOS裝置等等,請參考我們的裝置連線文件,在`AirtestIDE`里根據需要連線一個裝置。

成功連線裝置後,就可以根據Airtest指令碼錄製文件中描述的兩種功能:手工按鍵錄製與自動錄製,來錄製你需要的指令碼內容了。

同時可以通過使用Python的判斷、迴圈等語法,讓指令碼實現更加複雜的功能,完成自動化測試的需求。

Airtest指令碼示例

這是一個簡單的指令碼示例內容:(AirtestIDE中會自動將`Template(xxxx)`渲染為圖片形式)

# -*- encoding=utf8 -*-
__author__ = "user"

# 初始化環境
from airtest.core.api import *
auto_setup(__file__)

start_app("org.cocos2d.blackjack")

# 模擬點選
touch(Template(r"tpl1556019871196.png", record_pos=(0.204, -0.153), resolution=(1280, 720)))
sleep(2)
swipe(Template(r"tpl1561952588795.png", record_pos=(-0.067, 0.134), resolution=(1280, 720)), vector=[0.2783, 0.0374])
wait(Template(r"tpl1561952704834.png", record_pos=(-0.186, -0.093), resolution=(1280, 720)))

keyevent("BACK")

# 一些簡單的邏輯判斷
if exists(Template(r"tpl1559100640980.png", record_pos=(-0.33, -0.105), resolution=(1920, 1080))):
text("test")

# 斷言
assert_exists(Template(r"tpl1561952631660.png", record_pos=(-0.373, -0.108), resolution=(1280, 720)), "驗證內容存在")

stop_app("org.cocos2d.blackjack")

初始化環境

首先,就像一個普通的Python指令碼一樣,我們需要在程式碼檔案的最開頭部分,寫上`from airtest.core.api import *`,將Airtest的主要API都import進來,以便在後續指令碼中使用這些API。

`auto_setup` 是一個用來初始化環境的介面,介面文件在這裡,它接受4個引數,我們可以設定當前指令碼所在的路徑、指定執行指令碼的裝置、設定預設的log路徑和設定指令碼父路徑。

  • 如果`auto_setup`不傳入任何引數的話,Airtest將會讀取執行時命令列中傳入的各項引數,來對環境進行初始化。
  • 在AirtestIDE建立指令碼時,預設生成的程式碼裡是最簡單的初始化程式碼`auto_setup(__file__)`,意思是將指令碼檔案作為指令碼路徑傳入,其他引數內容將預設讀取執行命令列傳入的引數。

指令碼執行命令列有兩種形式,命令列中的引數包含`device`、`log`等:

  • 命令列執行Airtest指令碼的示例:`>airtest run untitled.air --device Android:///手機裝置號 --log log/`。更多使用命令列執行指令碼資訊,請參考文件。
  • 在使用AirtestIDE執行指令碼時,會在“Log檢視窗”中自動生成一個可用的命令列,可以供大家作為參考。
"D:\AirtestIDE-path\AirtestIDE" runner "D:\script-path\untitled.air" --device Android://127.0.0.1:5037/5PZTQWQOGES8RWUG --log "C:\Users\username\AppData\Local\Temp\AirtestIDE\scripts\aa8c71acdfa70c3068b862cb42ffb8dc"

 

裝置連線

  • 在執行時的命令列中如果傳入了類似`--device Android:///`這樣的裝置引數,那麼指令碼在初始化時會自動連上對應的裝置,不需要再另外寫程式碼連線了。
  • 如果沒有在初始化時連上裝置,可以在指令碼程式碼中使用`connect_device`介面來連線裝置。
  • Airtest支援在一個腳本里同時連線多個裝置,使用`set_current`介面可以在多個裝置中進行切換,`device()`介面可以獲取到當前使用中的裝置。

模擬點選

Airtest作為自動化測試框架,模擬的是人的操作,常見介面主要有:

  • `touch` 點選某個位置,可以設定被點選的位置、次數、按住時長等引數
  • `swipe` 從一個位置滑動到另外一個位置
  • `text` 呼叫輸入法輸入指定內容
  • `keyevent` 輸入某個按鍵響應,例如回車鍵、刪除鍵
  • `wait` 等待某個指定的圖片元素出現
  • `snapshot` 對當前畫面截一張圖
  • 其他

核心API請參見這個文件,在這個文件頁裡出現的API都是跨平臺API,由於我們在程式碼的第一行裡將`airtest.core.api`裡的介面全部`import`進來了,因此這些API可以在程式碼裡直接進行呼叫,像這樣:

from airtest.core.api import *
touch((x, y))

在很多介面中,支援傳入`Template`圖片物件作為引數,在執行時將會去點選圖片在畫面中的所在位置,類似這樣:

# 等價於 touch((x, y)), (x, y)是圖片所在的中心點
touch(Template(r"tpl1556019871196.png", record_pos=(0.204, -0.153), resolution=(1280, 720)))

其中,`Template`物件是一個圖片類,Airtest會先嚐試在當前畫面中尋找能夠匹配這張圖片的位置,如果找到了,將對這個座標進行點選操作,如果找不到,將丟擲識別異常。我們將在後文對`Template`圖片類進行更加詳細的介紹。

平臺相關的介面

剛才提到的`airtest.core.api`中的介面,都是跨平臺的,但是每個介面具體支援的平臺可能各不相同。例如,install介面在文件中的`支援平臺`一欄裡,只有`Android`,意味著在連了`Windows`裝置(即某個Windows視窗)時,是不能使用這個介面來安裝應用程式的。

具體檢視某個介面在某個平臺下的支援情況,請翻閱文件目錄中的`平臺相關的API`,根據具體的平臺查詢對應的介面,同時,還能發現在不同的平臺下,有一些獨有介面可供呼叫,例如在Android平臺下:

from airtest.core.api import *
# Android平臺下的touch介面支援額外的引數duration來控制點選螢幕的時長
# 翻閱airtest.core.android.android中的Android包含的touch方法來獲取更多引數資訊
touch((600, 500), duration=1)

# 在Android中,有一個平臺獨有的介面list_app可以列出所有安裝過的應用
dev = device() # 先獲取到當前裝置物件,這裡的dev即是一個Android物件
print(dev.list_app()) # 然後就可以呼叫平臺獨有介面了

斷言語句

斷言在單元測試程式碼中非常重要,因此建議在我們的腳本里使用斷言語句來判定被測應用當前的狀態是否是我們預期中的狀態。

Airtest提供了`assert_exists`和`assert_not_exists`兩個介面,來斷言一張圖片存在或不存在於當前畫面中。

同時,還提供了`assert_equal`和`assert_not_equal`兩個語句,來斷言傳入的兩個值相等或者不相等。

二、如何在Python指令碼中使用Airtest

AirtestIDE在新建指令碼時,也能夠直接建立一個`.py`指令碼檔案,但是在建立之前會彈出一個設定視窗,要求填寫一些指定的引數。

在我們瞭解過`auto_setup`介面後就會知道,這些引數就是為了傳給它,然後初始化Airtest執行環境用的。因此,一個純`.py`指令碼的初始化程式碼可以是這樣的:

from airtest.core.api import *
from airtest.cli.parser import cli_setup

if not cli_setup():
auto_setup(__file__, logdir=True, devices=[
"Android:///?cap_method=javacap&ori_method=adbori",
])

# do something
# touch((x, y))

上面這段程式碼的意思是說,當使用 `python xxx.py` 來執行本檔案,且不帶任何命令列引數時,則自動使用 `auto_setup` 這個介面來對airtest相關的引數進行初始化。這樣只需要在寫py指令碼時,填寫好指定的引數就能直接用 `python xx.py` 指令來執行指令碼。

同時,原先傳統的 `airtest run xx.air –-devices Android:///` 命令列執行方式也不受影響,只要指令碼檢測到傳入了命令列引數(即程式碼中的`if not cli_setup()`判斷),就依然優先使用命令列引數來初始化Airtest環境。

當然,熟練掌握API的各位,也可以根據實際需求在自己的Python指令碼中呼叫Airtest API,與使用正常的Python第三方庫方法相同。

三、圖片類`Template`的引數介紹

在AirtestIDE中,帶有截圖的語句是能夠展示出對應的圖片的,方便大家知道這個語句使用的是什麼截圖。在編輯器中點選滑鼠右鍵選單的`圖片/程式碼模式切換`,可以將當前編輯視窗中的程式碼切換成純文字程式碼,那麼我們將會看到,一個`touch(圖片)`這樣的語句,可能會變成這樣的格式:

touch(Template(r"tpl1556019871196.png", record_pos=(0.204, -0.153), resolution=(1280, 720)))

`Template`即Airtest封裝的圖片類,執行時會先去讀取這張圖片,然後在當前畫面中找到最符合這張圖片的座標點,最後才執行`touch`點選。

在AirtestIDE中截的圖,預設會自帶3個引數,第一個引數是圖片名,第二個`record_pos`記錄了擷取這張圖片時,它所在的位置,第三個`resolution`記錄的是擷取圖片時,當前畫面的解析度。

  • `record_pos`的作用是,可以讓Airtest在回放指令碼時優先在錄製時的位置附近查詢,如果找不到符合條件的圖片,再擴大尋找範圍到整個畫面。這樣能夠提升查詢圖片的速度和精確度。
  • `resolution`記錄的是畫面的解析度,如果在不同裝置上回放指令碼,Airtest將會對當前畫面的解析度按照比例進行一定的縮放,方便圖片的跨解析度匹配。
  • 雖然直接使用圖片路徑來初始化一個`Template`類,也同樣能夠執行程式碼,但是為了能夠適配更多解析度的裝置,以及提升影象查詢速率,建議各位儘量填寫引數。AirtestIDE擷取的圖片將會自動生成對應的引數,如果對擷取的圖片不滿意,可以使用圖片編輯器功能對圖片進一步修改。

除了以上三個引數之外,圖片還支援更多引數,對執行過程中的影象識別閾值、點選位置和是否灰度進行修改。其中,影象匹配的閾值`threshold`值與影象識別的成功率息息相關,請閱讀文件獲得更多細節。

#### 影象識別的全域性配置項

在上一小節中,我們介紹了影象模板類`Template`的各項引數,當我們修改那些引數時,只有對應的那張圖片會生效,舉個例子:

touch(Template(r"tpl1556019871196.png", threshold=0.9)

在這行程式碼中,我們將一張圖片的識別閾值`threshold`設定為0.9,意思是當識別結果的可信度大於等於90%時,我們才認為這次影象識別匹配成功,是一個相當嚴格的設定了。

假如我們希望能夠將這個設定擴充套件到整個指令碼中的所有圖片,又不希望挨個修改每張圖片的程式碼時,我們可以考慮修改Airtest的全域性配置來實現這個需求:

from airtest.core.api import *
# airtest.core.api中包含了一個名為ST的變數,即為全域性設定
ST.THRESHOLD = 0.8

# 未指定圖片threshold,預設使用ST.THRESHOLD中的0.8
touch(Template(r"tpl1532588127987.png", record_pos=(0.779, 0.382), resolution=(407, 264)))

# 手工指定圖片threshold,以圖片設定的0.6為準
touch(Template(r"tpl1532588127987.png", record_pos=(0.779, 0.382), resolution=(407, 264), threshold=0.6))

 

還有更多可定製的全域性配置項,請各位檢視指令碼全域性配置文件頁來獲取更多配置項的介紹。

總結

通過閱讀本節教程,希望大家能夠對Airtest指令碼有更加深入的印象,它不僅僅能夠在AirtestIDE上通過幾次滑鼠點選來生成錄製指令碼,還可以結合Python、運用程式設計技巧編寫程式碼實現更多複雜需求。

因此,使用Airtest與使用其他Python第三方庫一樣,需要多加閱讀Airtest API文件,而Github上的原始碼也清晰易懂,歡迎各位閱讀原始碼或與我們交