Python实现Appium读取短信验证码

最近在使用Appium做App自动化测试的时候,遇到需要读取短信验证码的场景。在网上查阅了很多资料,大致有以下几种方案:

  1. 通过下拉手机状态栏从消息中心获取短信验证码,或者打开短信App读取验证码
  2. 请开发帮助在测试环境写一个万能验证码
  3. 从数据库或者Redis缓存中读取已存储的验证码
  4. 自己写一个专用App读取手机的短信验证码并存储,然后每次从已存储的文件中读取验证码 (很佩服这种方式和能力)

方案1最让我担心的是通过UI的方式可能导致不稳定;方案2和3看起来要更容易些,但是在和开发讨论之后,发现2不是一个好的实践,3在我们的项目中不可行;方案4很棒,但是需要具备App开发的能力,作为一个只能勉强写写测试代码的QA,表示做不到啊T_T。

无奈之下本打算使用方案1,但却无意间在appium pro网站上发现了一个获取Android手机状态栏通知消息的官方实现(Retrieving Status Bar Notifications for Android Devices), 感觉整个世界都变美好了,哈哈。尝试之后发现这个方案很稳定,也很方便,只是需要做一些额外的配置。在这里对整个过程做一下记录,方便自己以后再次使用。

方案简单介绍

Appium Team通过Appium Settings Helper App实现了一种读取通知的方法。 Appium Settings Helper App 是一个在Appium会话启动时自动安装在手机上的小型应用程序,在在第一次连接手机进行测试时会自动安装。主要是用来弥补一些通过UiAutomator2或Espresso不可实现的设备级功能。

Appium Settings应用程序可以被授予阅读任何传入通知的权限。然后,它可以使用ADB保存这些通知,以便由Appium主进程检索。这个复杂的过程被封装在了一个Appium命令中(在Appium 1.16中首次发布):

driver.execute_script("mobile: getNotifications")

完整的实现分为以下四步:

1. 配置Appium Settings应用权限

下面的步骤仅针对三星手机,其他手机需自行百度。
设置 -> 应用程序 点击右上角的三个点 -> 特殊访问 -> 通知访问 打开Appium Settings的开关即可

2. 读取消息中心的消息

driver.execute_script("mobile: getNotifications")

读取的结果是一个字典,每一条消息都是一个键值对,且最新的消息在最前面。

3. 通过正则表达式提取验证码

将上一步的结果转换为字符串,然后使用正则表达式去匹配短信模版获取验证码。由于不能保证每次测试前消息中心都处于清空状态,所以可以获取所有的验证码,然后取其中的第一个。

class SmsCode(object):

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

    # 获取所有验证码
    def _get_all_codes(self):
        notifications = str(self.driver.execute_script("mobile: getNotifications"))
        pattern = re.compile(r'【某网站用户身份验证】您的验证码(\d{6}),该验证码5分钟内有效,请勿泄漏于他人!')
        self.codes = pattern.findall(notifications)
        return self.codes
    
    # 获取最新验证码
    def _get_code(self):
        return self.codes[0] if len(self.codes) else None

4. 循环等待新的验证码

在点击了发送验证码按钮之后,使用循环等待的方式去获取最新的验证码。

    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!')

你可能感兴趣的:(Python实现Appium读取短信验证码)