python+appium自动化测试-元素等待

Posted 蜗牛Tin

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了python+appium自动化测试-元素等待相关的知识,希望对你有一定的参考价值。

该篇文章主要用于整理的是在执行自动化测试过程中的几种元素等待方法

  • implicity_wait()
  • sleep()
  • wait_activity()
  • 等待某元素出现后,再执行操作
  • WebDriverWait()

一、implicity_wait()-以下案例为微博

隐式等待:属于全局的等待,它不是针对某一个元素,而是针对当前session(即当前driver对象的生命周期)的全部元素,所以只需要在构造driver对象时设置一次即可。

如果不发送此命令,则驱动程序应默认为隐式等待0s

appium官方文档的隐式等待

self.driver.implicitly_wait(5) # waits 5 seconds

隐式等待一般与启动app的设置中,存放位置如下图所示:

二、sleep()

强制等待:sleep()方法是python的time模块提供,所以需要导入:from time import sleep;当执行了sleep()方法后,会强制休眠,休眠的时间可以在括号中自己设置,括号里面的数字以秒为单位,例如休眠1秒:sleep(1),括号中也能用小数点表示,例如休眠1.5秒:sleep(1.5)

from time import sleep
# 强制休眠1秒
sleep(1)
# 强制休眠1.5秒
sleep(1.5)

三、wait_activity() -以下案例为QQ

wait_activity():判断需要执行的按钮所在页面的activity出现后,再对页面执行操作

#登录按钮所在的activity:com.tencent.mobileqq//.activity.LoginActivity
# 设置等待100S,每隔2S刷新一次,等待登录按钮所在的activity页面出现,current_activity指的是当前的activity页面
driver.wait_activity(".activity.LoginActivity",100,interval=2)
# 当前页面的activity
AC = driver.current_activity
print(AC)

**注:**如何获取当前页面的activity:cmd命令中输入:adb shell dumpsys activity activities

下图中红色框内的即表示当前页面的activity,下图为微博实例,所以当前页面的activity 为:com.sina.weibo/.SplashActivity

代码中做判断时可以简写为".SplashActivity"

四、等待某元素出现后,再执行操作-以下案例为QQ

该方法通过判断需要执行的按钮是否已经在页面中存在,若存在,则执行点击操作,若不存在,则输出内容

def check_LoginBtn():
    """等待登录按钮出现后做点击操作"""
    print("check_LoginBtn is running")
    try:
        LoginBtn = driver.find_element_by_id("com.tencent.mobileqq:id/btn_login")
    except NoSuchElementException:
        print("LoginBtn Element no Exist!")

    else:
        LoginBtn.click()

check_LoginBtn)             #调用函数

五、WebDriverWait()-以下案例为QQ

显示等待:WebDriverWait是webdriver提供的方法,该类提供的until()和until_not()方法再根据判断条件excepted_conditions进行等待,until()方法在返回为Ture时中断等待,until_not()方法在返回值为False时中断等待。与implicity_wait()不同的是,显示等待是针对单个元素定位进行等待,每隔一段时间检查需要定位的元素是否加载完成,超过参数规定的时间仍未定位到该元素,则定位该元素失败,抛出异常。

1.格式:WebDriverWait(driver,timeout,poll_frequency=0.5,ignored_exceptions=None)

driver:webdriver的驱动程序,如(IE,FireFox,chrom)

timeout:超时时间,默认以秒为单位

poll_frequency=0.5:休眠时间(步长)的间隔,默认为0.5秒,即检测元素是否存在的频率

ignored_exceptions=None:超时后的异常,默认情况下抛:"NOSuchElementException",可以定义忽略的异常信息
#lambda表达式相当于函数,表示在时长100秒内,直到找到这个id元素,就执行点击操作,WebDriverWait表示驱动
# WebDriverWait(driver,100).until(lambda driver:driver.find_element_by_id("com.tencent.mobileqq:id/btn_login"))
# driver.find_element_by_id("com.tencent.mobileqq:id/btn_login").click()

WebDriverWait(driver,100).until(EC.presence_of_element_located((By.ID,"com.tencent.mobileqq:id/btn_login")))
driver.find_element_by_id("com.tencent.mobileqq:id/btn_login").click()
#QQ演示WebDriverWait()元素等待
from appium import webdriver
from time import sleep
from selenium.common.exceptions import NoSuchElementException
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By

desired_caps = {"platformName": "android",
                "deviceName": "U4AIUKFAL7W4MJLR",
                "platforVersion": "9",
                "appPackage": "com.tencent.mobileqq",
                "appActivity": "com.tencent.mobileqq.activity.SplashActivity",
                "automationName": "UiAutomator2",
                "noRest": True
}

driver = webdriver.Remote("http://localhost:4723/wd/hub",desired_caps)

#登录id:com.tencent.mobileqq:id/btn_login

#方式四:WebDriverWait
#lambda表达式相当于函数,表示在时长100秒内,直到找到这个id元素,就执行点击操作,WebDriverWait表示驱动
# WebDriverWait(driver,100).until(lambda driver:driver.find_element_by_id("com.tencent.mobileqq:id/btn_login"))
# driver.find_element_by_id("com.tencent.mobileqq:id/btn_login").click()

WebDriverWait(driver,100).until(EC.presence_of_element_located((By.ID,"com.tencent.mobileqq:id/btn_login")))
driver.find_element_by_id("com.tencent.mobileqq:id/btn_login").click()

#账号元素:class:android.widget.EditText
#密码元素:id:com.tencent.mobileqq:id/password
def check_LoginText():
    """校验账号输入框是否存在"""
    print("check_LoginText is running")
    try:
        LoginText = driver.find_element_by_class_name("android.widget.EditText")
    except NoSuchElementException:
        print("LoginText Element no Exist!")
    else:
        LoginText.send_keys("111")
        driver.find_element_by_id("com.tencent.mobileqq:id/password").send_keys("222")

def check_PwdText():
    """校验密码输入框是否存在"""
    print("check_PwdText is running")
    try:
        PwdText = driver.find_element_by_id("com.tencent.mobileqq:id/password")
    except NoSuchElementException:
        print("PwdText Element no Exist!")
    else:
        PwdText.send_keys("222")

check_LoginText()
check_PwdText()

Appium python自动化测试系列之等待函数如何进行实战

?9.1 等待函数的使用

9.1.1 为什么要使用等待函数

我们在做自动化的时候很多时候都不是很顺利,不是因为app的问题,我们的脚本也没问题,但是很多时候都会报错,比如一个页面本来就有id为1的这个元素,可是我无论怎么定位他都没办法操作,然后报错,这个是怎么个情况呢?因为当我们app打开一个页面的时候我们的appium的运行速度过快那么可能害没有将页面的资源解析完成然后你就去操作了,这样能行吗?肯定不行的,这样不报错谁错呢?所以在很多的时候我们都需要加载等待时间的。那我们是不是盲目的去每个页面都加载等待时间呢?

9.1.2 什么时候使用等待函数

答案肯定是否定的,自动化的目的是高效,但是你每个页面都去添加等待时间那么执行下来的效率是不是大大降低了?估计你的领导该找你谈话了。在加载等待时间时我们需要根据自己的判断去增加,比如一些页面资源较多加载慢了那你肯定需要加的。是不是都是这样呢?其实不是的,所以这个就有了下面我们需要讲的知识点,几种不同类型的等待。

9.2 强制等待

9.2.1 什么是强制等待

故名思义就是你必须给我等,有点耍流氓的意思。比如:我进入到登陆页面,刚好有一个强制等待的函数,那么结果就是无论页面的资源加载完没有你都得给我等着。懂了吗?只要时间没到你就给我等着!哈哈,就像那啥一样蛮不讲理哈。

9.2.2 强制等待使用

在python里面这个比较好,他调用的是time包下的等待函数,代码如下:

#coding = "utf-8"
import time
time.sleep(10)

 

首先是需要导入time的包,下面一句话就搞定,是不是方便、实用呢?你调试程序的时候这样写写就好,千万别在实际项目中多用。因为这个time的等待是线程的死等,就是无论如何都会执行这一条语句,如果你在实际项目中去运行那么你会发现效率会很慢。所以实际项目不推荐。

备注:时间是按秒计算

9.2.3 强制等待封装实战

前面我们学了函数的封装,如果我们这个等待函数需要在很多地方用到是不是每个地方都要来这么一句呢?其实不是的,程序最重要的目的就是我们能够少写哪怕是一个单词我们都要进行封装,这是我的理解。实现同样的功能为什么不挑简单的方法做呢?对吧。看封装代码:

#conding="utf-8"
import time
from appium import webdriver
import os 
def Case(platformName,platformVersion,deviceName,app,appPackage,appActivity):
  PATH = lambda p: os.path.abspath(os.path.join(os.path.dirname(__file__), p))
  #print getConfig("baseconf", "platformName")
  desired_caps = {}
  desired_caps[‘platformName‘] = platformName #设置平台
  desired_caps[‘platformVersion‘] = platformVersion #系统版本
  desired_caps[‘deviceName‘] = deviceName #设备id
  desired_caps[‘autoLaunch‘] = ‘true‘ #是否自动启动
  desired_caps[‘noReset‘] = ‘true‘
  desired_caps[‘newCommandTimeout‘] = 20
  desired_caps[‘app‘] = PATH(app)#安装包路径,放在该py文件的目录下)
  desired_caps[‘appPackage‘] = appPackage #包名
  desired_caps[‘appActivity‘] = appActivity #启动的activity
  driver = webdriver.Remote(‘http://localhost:4723/wd/hub‘, desired_caps)
  waitFor(5)
      
#等待函数
def waitFor(t):
  time.sleep(t)

   看见这个代码大家是不是有种朦胧的感觉?其实这个就是上一章节让大家下去思考的,我将我们启动的参数做了一个简单的封装,然后将等待函数也进行了封装,然后他俩结合就成了现在的样子。是不是很简单?其实我想告诉你的是这个在真的自动化中不算自动化,但是大家需要慢慢的养成这个思维,多练习。在上面的代码中我们将我们启动app的代码进行了一个简单的重构封装,这个时候对于初学者来说强烈建议大家动手操作,不然你不知道你是否能够启动,而且上面各行代码什么意思一定要搞清楚。

 

9.3 隐式等待

  隐式等待可能对于刚学的人来说比较模糊,不知道是什么意思,大家可以这样理解,智能等待。为什么这么说呢,我们需要先了解了他的用处那么为什么这么叫也就很明白了,首先我们看下面的代码:

driver.implicitly_wait(10)

   上面代码就是隐式等待,他的语句就是这样很简单。但是你有思考过一个问题没,为什么这个等待是使用的driver?这里需要说的是因为这个等待函数是webdriver提供的一个等待函数。那么问题又来了,既然是webdriver提供的等待函数为什么没看到他指定需要的等待对象呢?有没有思考过这个问题呢?因为这里的等待函数是针对我们整个driver的。也就是说你只要是用driver去操作一个对象,或者一个元素,当你找不到这个元素或者对象的时候他就会自动的去等待你设置的这个超时时间,如果在超时时间内还没有找到,程序就会报错。是不是感觉这个等待太高大上了?还不动手练习去。

  可能又有人会提出疑问说:为什么你这了又driver,我没有啊,或者说我按照你强制等待那样将启动的封装了,然后隐式等待我也这样封装了,然后我这个就报错了,为什么?首先思考一下,你回去把我们生成driver的地方去掉封装,然后运行这样的一句话就不是就不会报错,尝试一下。但是封装就报错,为什么?因为我们这里没有把driver返回出去,也就是说我们需要用到的driver现在是没有被定义的,那么肯定会报错,那我如何和前面的代码一样封装呢?看下面:

#conding="utf-8"
import time
from appium import webdriver
import os 
def Case(platformName,platformVersion,deviceName,app,appPackage,appActivity):
  PATH = lambda p: os.path.abspath(os.path.join(os.path.dirname(__file__), p))
  #print getConfig("baseconf", "platformName")
  desired_caps = {}
  desired_caps[‘platformName‘] = platformName #设置平台
  desired_caps[‘platformVersion‘] = platformVersion #系统版本
  desired_caps[‘deviceName‘] = deviceName #设备id
  desired_caps[‘autoLaunch‘] = ‘true‘ #是否自动启动
  desired_caps[‘noReset‘] = ‘true‘
  desired_caps[‘newCommandTimeout‘] = 20
  desired_caps[‘app‘] = PATH(app)#安装包路径,放在该py文件的目录下)
  desired_caps[‘appPackage‘] = appPackage #包名
  desired_caps[‘appActivity‘] = appActivity #启动的activity
  driver = webdriver.Remote(‘http://localhost:4723/wd/hub‘, desired_caps)
  waitFor(5)
  return driver  
      
#等待函数
def waitFor(t):
  time.sleep(t)

#隐式等待
def implicit_for_wait(t):
 driver = Case(platformName,platformVersion,deviceName,app,appPackage,appActivity)
 driver.implicitly_wait(t)

 再回过头去看代码是不是发现了不一样的地方?这里我们将初始化的driver进行了一个闭包,也就是给出了一个返回值,然后我们在隐式等待中将我们的driver进行调用,然后他就拥有了driver,所以这个时候就能够像上面的代码一样进行调用该等待方法了。

9.4 显式等待

  前面我们讲了隐式等待和强制等待,下面我们看看显示等待,同样的先看代码:

WebDriverWait(driver, timeout, poll_frequency=0.5, ignored_exceptions=None)

 

首先我们来弄明白这个方法里面几个参数的含义:

1、driver:是我们操作的driver。

2、timeout:超时时间,也就是我们找这个元素要找多久

3、poll_frequency:间隔时间,怎么理解?就是说在超时时间内每多少秒去查询一次,默认情况是0.5秒一次

4、ignored_exceptions:异常,就是没有找到程序抛出什么异常。在默认情况是跑出:NoSuchElementException

在一般情况下我们只需要填写前面两个就行。看到这里是否发现一个问题,这个也没有定位元素,只是driver和时间。是不是也是全局的呢?答案肯定是否定的。在一般的情况下显式等待是需要和其他方法一起结合的,看下面完整的代码:

 

driver = self.driver
WebDriverWait(driver, 10,5).until(lambda driver:driver.find_element_by_id("ssss"))

 这个代码是不是又看不懂了?我们再接着按照刚才的方法把这个代码重构一下:

#conding="utf-8"
import time
from appium import webdriver
import os 
def Case(platformName,platformVersion,deviceName,app,appPackage,appActivity):
  PATH = lambda p: os.path.abspath(os.path.join(os.path.dirname(__file__), p))
  #print getConfig("baseconf", "platformName")
  desired_caps = {}
  desired_caps[‘platformName‘] = platformName #设置平台
  desired_caps[‘platformVersion‘] = platformVersion #系统版本
  desired_caps[‘deviceName‘] = deviceName #设备id
  desired_caps[‘autoLaunch‘] = ‘true‘ #是否自动启动
  desired_caps[‘noReset‘] = ‘true‘
  desired_caps[‘newCommandTimeout‘] = 20
  desired_caps[‘app‘] = PATH(app)#安装包路径,放在该py文件的目录下)
  desired_caps[‘appPackage‘] = appPackage #包名
  desired_caps[‘appActivity‘] = appActivity #启动的activity
  driver = webdriver.Remote(‘http://localhost:4723/wd/hub‘, desired_caps)
  waitFor(5)
  return driver  
       
#等待函数
def waitFor(t):
  time.sleep(t)
 
#隐式等待
def implicit_for_wait(t):
 driver = Case(platformName,platformVersion,deviceName,app,appPackage,appActivity)
 driver.implicitly_wait(t)

#显示等待
def wait(t):
  driver = Case(platformName,platformVersion,deviceName,app,appPackage,appActivity)
  WebDriverWait(driver, 10,5).until(lambda driver:driver.find_element_by_id("ssss"))
  

 这里python基础不好的读者会有一定困难,前面的不讲解。先看lambda后面的代码,他是一个匿名函数,冒号前面的是参数,冒号后面的是返回值,driver是我们需要传入的一个参数,类似下面的代码:

def appiumDriver(driver):
  return driver.find_element_by_id("xxxxx");

  他们俩的意思是一样的。接着看.until方法,他给出的解释是:调用该方法提供的驱动程序作为一个参数,直到返回值不为 False。那么整脚本的意识翻译过来是不是在10秒内每5秒去查找一个id为sss的元素,如果没找到那么就报错。

在自动化中我们需要的是不断去学习新的思想,程序永远是跟着思想走的,如果说你的思想很好了,那么脚本怎么实现就相对而言很简单了。

 

以上是关于python+appium自动化测试-元素等待的主要内容,如果未能解决你的问题,请参考以下文章

python+Appium自动化:元素等待时间

使用 Appium 和 Python 测试 iOS 应用程序时等待元素加载?

appium自动化测试等待的三种方法

appium+python搭建自动化测试框架_Appium元素定位

python+appium自动化测试-元素定位

Android自动化测试——Appium的使用