Python實(shí)現(xiàn)Appium讀取短信驗(yàn)證碼

最近在使用Appium做App自動(dòng)化測(cè)試的時(shí)候,遇到需要讀取短信驗(yàn)證碼的場(chǎng)景。在網(wǎng)上查閱了很多資料,大致有以下幾種方案:

  1. 通過(guò)下拉手機(jī)狀態(tài)欄從消息中心獲取短信驗(yàn)證碼,或者打開短信App讀取驗(yàn)證碼
  2. 請(qǐng)開發(fā)幫助在測(cè)試環(huán)境寫一個(gè)萬(wàn)能驗(yàn)證碼
  3. 從數(shù)據(jù)庫(kù)或者Redis緩存中讀取已存儲(chǔ)的驗(yàn)證碼
  4. 自己寫一個(gè)專用App讀取手機(jī)的短信驗(yàn)證碼并存儲(chǔ),然后每次從已存儲(chǔ)的文件中讀取驗(yàn)證碼 (很佩服這種方式和能力)

方案1最讓我擔(dān)心的是通過(guò)UI的方式可能導(dǎo)致不穩(wěn)定;方案2和3看起來(lái)要更容易些,但是在和開發(fā)討論之后,發(fā)現(xiàn)2不是一個(gè)好的實(shí)踐,3在我們的項(xiàng)目中不可行;方案4很棒,但是需要具備App開發(fā)的能力,作為一個(gè)只能勉強(qiáng)寫寫測(cè)試代碼的QA,表示做不到啊T_T。

無(wú)奈之下本打算使用方案1,但卻無(wú)意間在appium pro網(wǎng)站上發(fā)現(xiàn)了一個(gè)獲取Android手機(jī)狀態(tài)欄通知消息的官方實(shí)現(xiàn)(Retrieving Status Bar Notifications for Android Devices), 感覺整個(gè)世界都變美好了,哈哈。嘗試之后發(fā)現(xiàn)這個(gè)方案很穩(wěn)定,也很方便,只是需要做一些額外的配置。在這里對(duì)整個(gè)過(guò)程做一下記錄,方便自己以后再次使用。

方案簡(jiǎn)單介紹

Appium Team通過(guò)Appium Settings Helper App實(shí)現(xiàn)了一種讀取通知的方法。 Appium Settings Helper App 是一個(gè)在Appium會(huì)話啟動(dòng)時(shí)自動(dòng)安裝在手機(jī)上的小型應(yīng)用程序,在在第一次連接手機(jī)進(jìn)行測(cè)試時(shí)會(huì)自動(dòng)安裝。主要是用來(lái)彌補(bǔ)一些通過(guò)UiAutomator2或Espresso不可實(shí)現(xiàn)的設(shè)備級(jí)功能。

Appium Settings應(yīng)用程序可以被授予閱讀任何傳入通知的權(quán)限。然后,它可以使用ADB保存這些通知,以便由Appium主進(jìn)程檢索。這個(gè)復(fù)雜的過(guò)程被封裝在了一個(gè)Appium命令中(在Appium 1.16中首次發(fā)布):

driver.execute_script("mobile: getNotifications")

完整的實(shí)現(xiàn)分為以下四步:

1. 配置Appium Settings應(yīng)用權(quán)限

下面的步驟僅針對(duì)三星手機(jī),其他手機(jī)需自行百度。
設(shè)置 -> 應(yīng)用程序 點(diǎn)擊右上角的三個(gè)點(diǎn) -> 特殊訪問 -> 通知訪問 打開Appium Settings的開關(guān)即可

2. 讀取消息中心的消息

driver.execute_script("mobile: getNotifications")

讀取的結(jié)果是一個(gè)字典,每一條消息都是一個(gè)鍵值對(duì),且最新的消息在最前面。

3. 通過(guò)正則表達(dá)式提取驗(yàn)證碼

將上一步的結(jié)果轉(zhuǎn)換為字符串,然后使用正則表達(dá)式去匹配短信模版獲取驗(yàn)證碼。由于不能保證每次測(cè)試前消息中心都處于清空狀態(tài),所以可以獲取所有的驗(yàn)證碼,然后取其中的第一個(gè)。

class SmsCode(object):

    def __init__(self, driver):
        self.driver = driver
        self.codes = []

    # 獲取所有驗(yàn)證碼
    def _get_all_codes(self):
        notifications = str(self.driver.execute_script("mobile: getNotifications"))
        pattern = re.compile(r'【某網(wǎng)站用戶身份驗(yàn)證】您的驗(yàn)證碼(\d{6}),該驗(yàn)證碼5分鐘內(nèi)有效,請(qǐng)勿泄漏于他人!')
        self.codes = pattern.findall(notifications)
        return self.codes
    
    # 獲取最新驗(yàn)證碼
    def _get_code(self):
        return self.codes[0] if len(self.codes) else None

4. 循環(huán)等待新的驗(yàn)證碼

在點(diǎn)擊了發(fā)送驗(yàn)證碼按鈕之后,使用循環(huán)等待的方式去獲取最新的驗(yàn)證碼。

    def wait_for_new_code(self):
        old_codes = self._get_all_codes()
        print(old_codes)
        for i in range(30):
            time.sleep(3)
            new_codes = self._get_all_codes()
            print(new_codes)
            if len(new_codes) > len(old_codes):
                return self._get_code()
        pytest.fail('SMS code not received within 90 seconds!')
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容