python自动化之selenium以及接口自动化

Posted 素七七吖

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了python自动化之selenium以及接口自动化相关的知识,希望对你有一定的参考价值。


vscode下载selenium,seleniu环境配置https://blog.csdn.net/weixin_34402408/article/details/88724699

八大元素定位

基于标签的属性来定位标签


frameset(框架集):忽略;frame(框架)和iframe(子框架)是需要处理的
八大元素定位是指,id、name、link text、partial link text、classname、tagname、cossselector、xpath

id、name

id,基于元素属性里面的id的值来定位,类似于每个人的身份证号,是不重复的
name,基于元素属性里面的name的值来定位,类似每个人的姓名,是可以有重名的

link text、partial link text

link text,主要用于超链接进行定位

partial link text是link text的模糊查询版本,类似于数据库中like %,模糊查询匹配到多个符合条件的元素,选取第一个
想找的第二个或者别的元素driver.find_elements_by_partial_link_text("百度")[1](get到百度网址)

classname、tagname

classname,基于元素样式来进行定位,容易遇到重复的
tagname,标签名进行定位,重复率最高,只有在需要定位后进行二次筛选的时候进行使用

cossselector、xpath

cossselector定位,应用相对较多,基于class属性来实现的定位,定位的内容可以直接copy选择selector(#id em[class=''])
xpath,是目前应用最多的,基于页面结构来进行定位

xpath相对路径,基于匹配制度来查找,依照xpath语法结构
例如://*[@id='kw'](//表示从根路径下开始查找;*表示任意元素;[]表示筛选条件/查找函数;@表示基于属性来筛选,例如@id='kw'表示基于属性id的值为kw的条件来查找)

在浏览器console里面也可以写xpath语句来定位,确认xpath路径是否正确,在F12界面Ctrl+f填入写的语句查找或者在console界面写入语句

根据文本定位 例如://a[text()="登录"]
当无法直接定位某个元素时,可以通过定位子元素返回父级来获取元素(末尾加上/..来返回上一级)

除了xpath写法外还有函数写法,//input[contains(@id,'kw')],contains表示匹配模糊查找,id的值包含kw
文本定位,//input[contains(text(),'XXXXX')]
//*[start-with(@id,'XXX')]属性值以XXX开头
//*[substring(@id,2)='XXX'],截取值,从第二个字符开始截取后的值为XXX

其他特殊定位处理

有框架的定位处理

有框架要先进入框架
driver.switch_to.frame("frame名/id"),然后再进行对框架内的元素的定位
对于没有id和name的框架用xpath定位,传入WebElement对象
iframe=driver.find_element_by_xpath('//*[@id="bjui-navtab"]/div[3]/div/iframe')
driver.switch_to.frame(iframe)

也可以用WebElement对象来定位
driver.switch_to.frame(driver.find_element_by_tag_name("iframe")) 
出框架:driver.switch_to.default_content()

下拉框的定位

先定位,定位之后转化为下拉框的select对象(要导入包from selenium.webdriver.support.select import select)
通过value值进行定位下拉框里的元素选择

还可以通过select_by_visible_text(绝对文本内容)来定位选择下拉框里面的元素,例如:sel.select_by_visible_text("50")
绝对文本内容就是所有的文本信息,连空格(&nbsp)也是文本内容,但是有类似空格这种特殊符号,可能该方法就无法定位选中
也可以通过select_by_index(下标)来进行定位选择下拉框内的内容,下拉框元素的每个option都有对应的下标志,第一个是0往下递增

弹窗处理

alert弹窗

弹窗有alert(只有确定),confirm(有确定有取消),prompt(有确定取消还可以输入值)
ale=driver.switch_to.alert
ale.accept()[点击确定,dismiss()是点击取消,send_keys()是输入值,text()是获得弹窗的文本]

其他弹窗

有的弹窗不是alert等的类型,但是也会只显示一会就消失
由于不是alert弹窗,无法使用switch_to方法。只能使用元素定位去获取text(),为了避免我们正在获取时,元素就提前消失了,导致报错。
可以先采用ActionChains模块的方法move_to_element()方法鼠标悬浮在弹窗上,这样弹窗就不会消失,然后去定位弹窗文本
from selenium.webdriver.common.action_chains import ActionChains	

loc = driver.xxxx 		# 首先我们获取该元素定位
action_chains = ActionChains(drver)
action_chains.move_to_element(loc).perform()	#  鼠标悬浮在该弹窗,防止弹窗消失
message = drver.text(loc)	#  text()获取弹窗元素文本
print(message)

div文本获取

当我们使用selenium获取div标签下的文本时, 应该使用get_attribute('innerText')
div  = browser.find_element_by_xpath('你的div path')
text = div.get_attribute('innerText')
text即为div下的文本

鼠标和键盘操作

文件上传操作

定位到选择文件夹后不使用click方法而是直接send_keys("文件地址"),这样就可以上传文件了

页面切换

有时候,例如像进行QQ登录的时候会打开新的页面,需要在新的页面进行操作,这是需要进行页面切换
handles = driver.window_handles          #获取当前浏览器的所有窗口句柄
driver.switch_to.window(handles[-1])     #切换到最新打开的窗口
driver.switch_to.window(handles[-2])     #切换到倒数第二个打开的窗口
driver.switch_to.window(handles[0])      #切换到最开始打开的窗口
#点击QQ登录
driver.find_element_by_partial_link_text("QQ登录").click()
# 获取当前所有标签页句柄
wins = driver.window_handles    # 返回的是一个列表,按照标签页打开的顺序
# 切换到第二个标签页
driver.switch_to.window(wins[1])
time.sleep(2)
#进入框架
driver.switch_to_frame(0)
#点击头像登录
driver.find_element_by_id("img_out_2356823260").click()
# driver.switch_to.window(wins[0])

基于网易云的登录自动化实战

网易云手机号登录自动化
最好使用from selenium.webdriver.common.by import By的语法(便于封装)
例如:driver.find_element(By.XPATH,"//a[text()='登录']").click()
from selenium import webdriver
from selenium.webdriver.common.by import By
import time
#创建浏览器对象
driver = webdriver.Chrome()
#隐式等待5秒
driver.implicitly_wait(5)
#网易云登录自动化
driver.get("https://music.163.com/")
#最大化当前页面
driver.maximize_window()
#定位元素
#定位登录
driver.find_element(By.XPATH,"//a[text()='登录']").click()
#定位选择其他登录模式
driver.find_element(By.XPATH,"//a[text()='选择其他登录模式']").click()
#定位同意协议勾选框
driver.find_element(By.XPATH,"//input[@id='j-official-terms']").click()
#定位选择手机号登录按钮
driver.find_element(By.XPATH,'//a[@class="u-btn2 u-btn2-2"]').click()
#定位输入账号
driver.find_element(By.XPATH,"//input[@id='p']").send_keys("账号")
#定位输入密码
driver.find_element(By.XPATH,"//input[@id='pw']").send_keys("密码")
#定位登录按钮
driver.find_element(By.XPATH,"//a[@class='j-primary u-btn2 u-btn2-2']").click()
#停留,保持在页面
os.system('pause')
#退出网页
driver.close()

51job自动搜索python并且把结果输出或者写入表格
先定位输入框输入内容
再定位选择城市,先将已经选择的(class-on)取消选择,再选择自己想要的城市
定位搜索按钮点击
定位结果

结果写入excel

unittest框架自动化

vscode中运行unittest框架:
创建python单元测试文件,包含test;文件名必须要包含test,否则将无法识别为unittest框架文件

按Ctrl+Shift+p,打开vscode命令选板,输入命令“Python:Configure Tests”,然后回车,进入配置

选择unittest框架和方法命名方式

打开控制台,可以看到控制台中已经包含了unittest方法

使用unittest方法
写一个类继承unittest.Testcase
导入unittest包
定义一个以test开头的方法,方法里面写自动化代码(选择的命名方式是以test开头就必须以test开头,其他方法的命名与其对应规则对应)

命令行的运行方式:python -m unittest python文件名(会运行所有子测试方法,例如:python -m test_autom.py)
只运行其中一个:python -m unittest python文件名.TestCase.类名(例如:python -m test_autom.TestCase.test_login)

设计模式(封装)

pom+关键字封装
pom模式:page object model 页面对象模式
能够解决线性脚本的问题、代码不能重复利用的问题、后期维护的问题
分为三层:
1.基础层(base):放selenium的原生方法;
2.页面对象层(po):主要用于放页面的元素和页面的动作;
3.测试用例层(testcase):存放测试用例以及测试数据
测试用例层调用页面对象层的方法,页面对象层调用基础层的方法

新建一个base层的类将原生方法进行封装

创建页面对象的类直接继承刚刚的基础类,写入页面元素与页面动作

测试用例层调用页面层的方法来实现代码

前后置处理

setUp和tearDown

setUp在测试用例之前的准备工作
tearDown在测试用例之后的扫尾工作(U和D一定要大写,孩子被坑哭了,pytest是小写)
新创建一个baseutil类在里面继承unittest.TestCase方法,写入setUp和tearDown,
在测试用例层的login里面就不用继承unittest.TestCase,直接继承baseutil类里面的方法
需要注意的是__init__()方法的改变,以及调用方法时要传递driver参数,page类没有改变


setUpClass和setDownClass

setUpClass和setDownClass是在每个类之前要执行的工作,在当前类的每个用例之前和之后只执行一次
常用于setUpClass创建日志对象,创建数据库连接,创建接口的请求,setDownClass用于销毁(pytest是setup_class/teardown_calss)

生成报告

执行需要的用例并且生成html格式的测试用例报告
在网上下载HTMLTestRunner.py的文件放到python的lib目录下

断言

self.assertEqual(first, second)用于判断两个值是否相等
self.assertTrue(expr)用于判断一个值是否为True
self.assertIn(member, container)用于判断一个值是否在另一个值里面

当断言定位的是一个动态的会出现一会就消失的弹窗时,使用了数据驱动,有的数据输入后提交会弹出弹窗,有的则不会,这时就需要利用try expect语句
...
global addsuccessValue
        element_existance = True
        try:
            # 尝试寻找元素,如若没有找到则会抛出异常
            element = self.locator_element(CumPage.allsuccess)
        except:
            element_existance = False
        if element_existance:
            addsuccessValue =self.get_attribute(CumPage.allsuccess,'innerText')
    #断言
    def get_except_result1(self):
        return addsuccessValue

DDT+Excel数据驱动

Excel适用于web自动化,yaml适用于接口自动化
data driver test数据驱动测试,可以完美和unittest结合实现数据驱动
DDT通过装饰器来使用,在函数或者类上面加上一个装饰器来实现特定的功能
@ddt 装饰类,用于声明当前类使用ddt驱动;@data 装饰函数,用于函数传值;@unpack 装饰函数,用于数据解包;@file_data 装饰函数,用于读取yaml、json文件
先写好Excel文件,写入数据后将Excel文件拖入自己所创建的自动化项目的文件夹下

使用@data传值的时候传递多个值就会执行多次,修改Excel的sheet值为login
写一个excelutil的工具类来实现将Excel里面的数据改为['XX','XX','XX']格式,在用例类里面使用@ddt,@data,@unpack
使用openpyxl,没有该包就先下载,pip3 install openpyxl

传递空值的时候回报错,因为NoneType的特殊性,加上if语句将None改为""

pytest

可以结合allure生成定制版的测试报告,支持很多强大的第三方插件(allure-pytest,pytest-xdist,pytest-ordering ……)

想要同时下载多个插件的话,就可以新建一个txt文档,将要下载的插件写入文档,一个插件名称占一行
然后在控制台输入 pip install -r 文件名(pip不可以的话用pip3),就可以同时下载文档里面写入的插件

默认规则

模块名必须以test_开头或者_test结尾
测试类必须以Test开头,并且不能有init方法
测试方法必须以test开头

执行(运行)

主函数和命令行

pytest的默认执行方式是根据自己写的方法从上到下依次执行,如果想要规定谁先执行或者指定执行顺序的话,可以使用标记
在想要规定顺序的方法前面加上@pytest.mark.run(order=num)[num是自己指定的,如果想要第一个执行,num就是1]



–html ./report/report.html:生成html报告

pytest.ini文件执行

实际中最主要的执行方法是写一个pytest.ini文件(写完后借助工具改为ANSI编码),放在项目跟目录,然后直接控制台输入pytest 即可
在这个文件里面写入测试文件夹,测试的参数,配置测试搜索模块文件名称以及测试类名和测试函数名(转编码格式时把中文去掉)
形成测试报告了可以在参数里面再写入 --html ./report/report.html;在report目录下生成report.html的报告

分组执行

在进行冒烟执行和分模块执行以及分接口和web执行时,在方法前面我们都会加上对应模块的标记,比如@pytest.mark.smoke;@pytest.mark.usermanage
在pytest.ini文件里面加入markers的值如下图
执行方式就是pytest -vs -m "smoke";同时执行两个就是pytest -vs -m "smoke or usermanage"

跳过测试用例

有的测试用例想要在执行的时候跳过,就在该用例的方法前面加上@pytest.mark.skip(reason="XXXX")[原因可写可不写]
需要写有条件跳过的话就是@pytest.mark.skipif(判断条件,reason="XXXX")[例如:@pytest.mark.skipif(age>18,'已成年')]

fixture装饰器

fixture装饰器是pytest的一个用于实现部分以及全部用例的前后置的工具
@pytest.fixture(scope="",params="",autouse="",ids="",name="")
(1)scope表示的是被@pytest.fixture标记的方法的作用域。function(默认) , class,moduile ,package/session.
(2)params 参数化,支持列表[],元组(),字典列表[,,],字典元组(,,)
(3)autouse=True :自动使用,默认False,自动使用的话就是所有的函数和类都会使用
(4)ids :当使用params泰数化时,给每一个值设置一个变量名。意义不大。
(5)name:给表示的是被@pytest. fioxture标记的方法取一个别名。使用别名后就不能再使用它本身函数的名字来调用了

scope的级别是class就是类级别的前后置,model表示在每个模块只会执行一次(一个模块可以有多个类,一个类可以有多个函数)
前置后置就是写玩前置的内容后用yield分隔写后置内容

在装饰器里面是params="",是参数名要s,在下面使用的param是属性名

import pytest
pytest.fixture (scope='function ' , params=[ '成龙''甄子丹''菜10'])
def my_fixture (request):
	print(前置')
	yield request.param
#return和yield都表示返回的意思,但是return的后面不能有代码,yield返回后后面可以接代码。
	print(后置)
class TestMashang1:
	def test_o1_ baili (self):
		print ( '\\n测试百里')
	def test_02_xingyao (self,my_fixture):
		print( '\\n测试星瑶')
		print ( ' -----―-----―--'+str(my_fixture))

conftest.py和fixture装饰器结合实现全局的前置应用

我们可以通过conftest.py和fixture结合来实现全局的前置应用,比如项目的全局登录,模块的全局处理
conftest.py是单独存在的配置文件,名称不能更改
使用conftest.py就可以跨文件使用前置
原则上conftest.py需要和运行的用例放到同一个层,并不需要import操作(不同层也可以做到)

修改为pytest形式

在pytest中setup和teardown是小写的u和d,只需要在用例类的函数前加上 @pytest.mark.parametrize()
括号里面写上数据("index,username,password",ExcelUtil().read_excel())数据解析直接"index,username,password",有几个参数就写几个
pytest的断言是直接assert(assert lp.get_except_result()=='welcome')


生成报告

先安装pip3 install allure-pytest 


去官网下载allure2并配置环境https://www.jianshu.com/p/078c2e856a83
配置好了重新打开vscode就可以正常运行了

生成allure报告第一步生成json格式的临时文件也可以就在 pytest.ini文件文件中的参数里面写入 --alluredir  ./temp来完成

pytest+yaml接口自动化

先pip3 install requests下载requests以及pyYaml

yaml文件格式:
1.MAP(键值对):键:(空格)值
2.列表list(数组):用一组横线开头
yaml文件的拓展名可以是yaml或者yml


Map写法

数组写法

yaml写用例一般以"—"开头,因为用例可能有多种,有正确的用例和错误的用例,以"—"开头代表是列表

简单天气接口实例

先在yaml文件里面写好接口的信息

ow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ3OTMyMzk3,size_16,color_FFFFFF,t_70)

- name: 获得城市实时天气的接口
  request:
    url: https://tianqiapi.com/free/week
    method: GET
    data:
      appid: 46697786
      appsecret: TBl83rKf
      city: 重庆
写一个pytest的python文件(命名一定要test_开头或者_test结尾)

添加pytest的数据驱动装饰器,使用刚刚写的yaml文件导入数据,写一个python函数读取yaml文件里面的值,利用函数导入数据到装饰器
	yaml读取后的数据是字典列表

import yaml
def read_yaml(yamlPath):
    with open(yamlPath,encoding='utf-8') as f:
        value=yaml.load(f,Loader=yaml.FullLoader)
        return value
if __name__ == '__main__':
    print(read_yaml())
导入模块后在装饰器里使用读取yaml文件的方法,导入数据

数据导入后就实现requests来发送请求,requests的请求传递参数有两种方式,data和json
data:只能传输字符串或者是非嵌套的字典。(非嵌套:'city":'深圳;嵌套: city :city":'深圳另)
json:只能传输字典

import pytest
from yaml_util import read_yaml
import requests
class Test_api:
    @pytest.mark.parametrize("data",read_yaml('test.yml'))
    def test_weather(self,data):
        # print(data)
        # print(data['name'])
        # print(data['request']['url'])
        # print(data['request']['method'])
        # print(data['request']['data'])
        # print(data['validate'])
        res=requests.get(data['request']['url'],data['request']['data'])
        #print(res.text) #文本字符串
        print(res.json()) #json格式
if __name__=='__main__':
    pytest.main(['-vs'])

以上是关于python自动化之selenium以及接口自动化的主要内容,如果未能解决你的问题,请参考以下文章

python自动化之selenium以及接口自动化

自动化测试之python----selenium测试环境搭建

[Python自动化]selenium之文件批量下载

Python3+Selenium3+Unittest+ddt+Requests 接口自动化测试框架

[Python自动化]selenium之验证码识别

Python3-Selenium自动化测试框架之xpath元素定位