B/S架构和C/S架构区别
HTTP协议
超文本传输协议,应用层协议,由请求与响应组成。
常见的请求方式有POST/GET,常见的状态码200ok,301永久移动,302临时移动,404找不到资源,500服务器内部错误。
POST与GET区别
Cookie和Session的区别与联系
cookie是存放在浏览器上而session是存放在服务器上的。
cookie不是很安全,涉及到用户隐私方面尽量存放在session中。
当访问量增多时,session会更加占用服务器资源。
测试的目的
发现软件的缺陷与漏洞,对软件的质量进行评估,提升软件质量。
软件测试原则
软件测试分为哪几个阶段?
单元测试、集成测试、系统测试、验收测试
单元测试与集成测试的侧重点
单元测试是对程序最小可测试的模块进行测试
集成测试是把各个模块连接起来时,穿越模块接口的数据是否会丢失。
系统测试范围
功能测试、用户体验测试、性能测试、UI测试、兼容性测试、安装测试、文档测试、稳定性测试等
a测试与ß测试的区别
a测试:公司组织的内部人员进行的测试
ß测试:公司组织的典型客户在实际生活中使用。
验收测试怎么做?
在UAT测试之前,我们会制定测试方案,选择基线用例,即级别高的用例,在UAT测试环境上进行测试,如果测试通过,验收测试就通过了。
白盒、黑盒和灰盒测试区别
白盒测试:对程序的内部结构与算法进行的测试
黑盒测试:不考虑程序的内部结果,只检查程序是否实现了需求的功能
灰盒测试:关注系统接口所实现的功能,是否和需求一致。
冒烟测试的目的
检查程序的基本功能是否正常
回归测试怎么做?
首先,把bug单对应的用例执行一遍,还要检查有数据交互的模块会不会受影响,有没有引入新的问题;项目上线前,还要把当前版本的重要功能以及冒烟测试的用例都回归一遍,确保重要功能上线后不出问题。
全部回归与部分回归的区别?
全量回归:对软件的新版本测试时,重复执行上一个版本测试时使用的测试用例,防止以前没有的问题现在出问题了
部分回归:当开发修复某个bug时,我们需要去检查该bug是否被修复,还需要检查与之相关联的模块是否受到影响。
需求分析的目的
澄清需求,提取测试点
测试计划的目的
规范软件测试内容、方法和过程
什么时候开始写测试计划
需求分析之后
由谁来编写测试计划
一般都是由测试经理或者测试组长来编写
测试计划的内容
测试项目的背景、测试范围和测试策略、测试环境、测试开始和结束条件、进度安排,测试组织,以及与测试有关的风险等方面的内容。
结束条件(项目上线的条件)
需求的覆盖率、用例的执行率和缺陷的遗留率达到质量目标。
通常来说:需求覆盖率和用例执行率需要达到100%
致命/严重的缺陷需要当天解决,轻微/一般遗留率不得超过30%
常见的测试风险
进度风险、质量风险和需求变更
测试用例的要素
用例编号,用例名称,级别,预置条件,测试步骤,期望结果
测试用例级别的划分
一般是依据用户使用该场景的频率,和该功能对系统的影响程度来确定
怎样保证覆盖用户需求?
项目开始前,我们会先熟悉需求,画好流程图,保证整个流程都覆盖全面,小组之间每个人都要根据各自的流程图,各个功能点有哪些限制条件,来讲解一下自己对测试点的理解,防止之后编写测试用例时出现遗漏;用例编写完之后,再进行用例的评审,看看测试点有没有用遗漏,对需求理解有没有错误,测试场景是否覆盖完全。
写好测试用例的关键 /写好用例要关注的维度
测试用例的状态
英文 | 中文 |
---|---|
No Test | 未执行状态 |
Pass | 通过状态 |
Fail | 失败状态 |
Block | 阻碍状态。 |
Investigate | 观察中状态。 |
常见的测试用例设计方法
判定表用在哪些时候/哪些功能
什么时候用到场景法
测试环境怎么搭建的?
参考答案:搭建环境前,开发都会给到我们一份系统发布手册,我们会根据这个手册来搭建。比如,我这个xx系统,是搭建在Unix系统下的,web服务器用的是Tomcat8,MySQL版本是5.7,程序是JAVA编写的,首先我们向开发拿到编译好的安装包,然后用xshell(或CRT)远程连接上Unix系统,把tomcat服务器停掉,把程序包放到webapps目录下,然后再启动tomcat服务器就可以了。
偶然性问题的处理
当我们认为某个地方是bug,但开发认为不是bug,怎么处理?
产品在上线后用户发现bug,这时测试人员应做哪些工作?
二八定理
80%的缺陷出现在 20%的模块。
如何跟踪缺陷
当发现缺陷后,我们要在禅道上提交问题单给开发,并每隔一段时间(间隔一个小时,或两个小时都可以)去检查缺陷是否被处理,如果没及时处理,就要提示开发,让开发及时修复问题,问题修复后,要及时进行回归测试。
缺陷的状态
激活,确认,已解决,关闭
缺陷的等级
致命,严重,一般,轻微
缺陷单应该包含这些要素
缺陷标题,严重级别,问题所属模块,复现步骤,预期结果,实际结果,有关的日志和截图。
测试报告的主要内容
人力投入,用例统计,问题单分类统计,遗留bug情况,测试风险,测试对象评估,测试结论
如何定位bug:
开发没时间修复,如何推进bug的修复:
软件测试流程
我们这个项目是两个人负责测试的,按模块进行分工,我负责xxx模块。项目启动后,我们会到服务器上下载相关的需求文档,熟悉项目的流程,进行需求澄清,提取测试点;然后编写测试用例,再进行组内的评审,修改,定稿;在开发阶段,开发人员写完一个接口,我们就测试一个接口;等开发转测后,我们从svn上获取安装包,搭建测试环境;之后我们开始进行冒烟测试,冒烟通过后,我们就进入SIT测试,之后进行UAT用户验收测试,验收通过后,编写测试报告。
项目介绍
参考思路:项目叫什么名字,什么架构,有哪些模块,用来干什么的,主要的操作流程
参考:我就说一下最近的一个项目,是集书芸管理系统,主要是一款基于B/S架构的电商分销管理系统,前台模块有店铺首页,购物车,会员中心,申请分销等,后台模块有店铺管理,书籍管理,订单管理,分销管理等,在后台可以上架新的商品,设置店铺活动,管理订单等,用户可以在前台注册成为会员,然后登陆系统,搜索上架的商品,将商品加入购物车之后进行结算下单,或者直接进行结算下单,下单后在用户的‘我的订单’能看到该订单信息,订单状态为待付款,在系统后台的订单管理列表也能看到该订单的信息,买家付款后,订单状态为待发货状态 ,卖家就可以进行发货,买家收到产品后进行确认,评论,整个购物的流程就结束了。这就是我这个项目的大概情况。
对一支圆珠笔进行测试,要从哪些方面进行测试?(扩展:还有可能是对一个水杯,一个注册功能,登陆功能,电梯等,进行测试。)
对任何东西测试一定要从质量的各个方面去说
三角形测试用例设计
解题思路
我们可以设三角形的3条边分别为A,B,C。如果它们能够构成三角形的3条边,必须满足:
A B C均是正数且大于0,还需满足
在项目中发现哪些经典bug?什么原因导致的?
一个项目完成时,有多个重要的缺陷没有被修复,但是项目负责人说可以不修改,你认为测试是不通过的,请简述你的理由。
测试是对软件的质量进行的把关,如果一个项目仍然有很多的缺陷未被修复,那么从质量的角度上我们会认为这个软件质量是不达标的,一般来说缺陷的遗留,是不允许严重、致命bug的遗留,轻微和一般的bug遗留率不超过30%。
在需求文档不太详细的情况下,如何开展测试?
如何尽快找到软件中的bug?
什么是bug?
ATM机吞卡的吞卡现象是不是BUG?
不一定,看是什么情况下吞卡。如:输入三次密码错误吞卡是正常的,不属于BUG;若输入一次密码错误吞卡则是不正常的,属于BUG。
如何减少非问题单的提交?
有个程序,在windows上运行很慢,怎么判断是程序存在问题,还是软硬件系统存在问题?
将程序放在其他的windows上运行,如果运行的还是很慢则是程序的问题。
你们发现bug会怎么处理。
答:发现bug后,我们会先自己定位一下,比如,抓个包,看看是前端的问题,还是后端的问题,检查下数据库的数据是不是正确的,尽量把问题发生的原因或者产生的日志找出来,方便开发定位问题,然后就提单给开发,然后开发做出相应的处理,开发修复完后就进行回归测试,回归测试通过后就关闭这个bug,没有通过就继续给回开发修复。如果遇到开发认为这个不是bug的话,那么我们就要和开发沟通,然后我们要坚持自己的立场,通过讨论后一致认为是bug就给开发修复,不是就关闭这个bug。如果开发和我们意见一直不一致,那么就要将问题升级,召集开发经理和测试经理一起讨论,再做决定。
从功能方面考虑:
从性能方面考虑:
从安全性方面考虑
从用户体验方面考虑
兼容性
订单怎么测试?(主要测试订单的状态变化)
我们系统的订单生成的流程是这样子的,用户下单后,系统会在用户端和卖家端生成一个待付款的订单,同时在数据库也会生成一个待付款的订单;当用户付款之后,用户端显示待发货状态,卖家端显示已付款待发货状态,订单在数据库的状态为待发货,产品相应的库存量会减少,用户的账户金额减少相应的金额;当卖家发货后,用户端和卖家端的订单状态都显示为配送中,数据库中的订单状态也同时发生变化;当用户确认收货后,订单状态会显示为已完成,待评价状态,数据库中的订单状态也同时发生变化,买家支付的款项会打入到卖家的账户;当用户评论完后,订单状态显示为已结束,数据库中的订单状态也同时发生变化。这是一个正常的流程,我们测试的时候,要优先把这个流程测试通过。
然后再考虑用户的其他使用场景,比如:
- 用户体验:
- 安全性:
- 兼容性:
- 性能:
- 可靠性:
举例来说一下你的自动化测试是怎么做的?
参考答案:就拿简历上的xxx项目来说吧,在编写脚本前,我们会对系统进行评估,确认这个系统可不可以实现UI自动化,如果可以的话,就筛选出能实现自动化测试的用例,一般优先把冒烟测试用例的转为成脚本。我们是用selenium工具来实现自动化,采用python脚本语言,基于unittest框架进行用例的编写。比如,下单这个功能的脚本,我们是这样做的:首先,我们会构建一个测试工程,测试工程包含testcase,主要用来存放测试用例,report用来存放测试报告,其次我们会把用例中公共的部分封装到public中,最后用runAllCase的python文件运行项目自动化用例,脚本调试完后,我们会用jenkins持续集成工具,设置脚本每天晚上10点跑一遍脚本,跑完后生成html格式的自动化测试报告。
自动化脚本失败的原因:
测试脚本用到了哪些技术?
参考答案:元素定位,表单切换,模块调用,JS定位等等,脚本是基于python自带的unittest单元测试框架,采用了模块化方式编写,把复用性高的操作封装到公共模块中,如果脚本需要用到对应的操作,直接调用就可以了,如果元素发生变化,只需要调整元素封装的代码就可以了,提高测试用例的可维护性。
xpath和CSS定位方式的区别:
1、语法不一样;
2、CSS定位比较稳定。
脚本怎么组织的?(编写自动化脚本,你的思路是什么?)
参考答案:构建一个测试工程,测试工程包含testcase,主要用来存放测试用例,report用来存放测试报告,其次我们会把用例中公共的部分封装到public中,最后用runAllCase的python文件运行项目自动化用例。测试脚本使用的是python的unittest单元测试框架组织管理,将所有测试脚本通过单元测试框架组织起来运行,这样做的好处是,维护起来方便,可以生成测试html格式的测试报告,报告包括:测试用例,通过数,失败数。
自动化率多少?
一般是30%到40%,这个没有固定的,我们是优先将优先级高的测试用例,比如,冒烟测试的测试用例转换成自动化脚本的,后面有时间的时候再不断补充,能写多少写多少。
自动化脚本的通过率是多少?(注意这个题目的意思)
参考答案:这个说不准,如果没有什么异常情况,自动化脚本都是100%运行通过;如果异常情况比较多,比如出现测试环境不稳定,或者开发修改了代码没通知到测试人员及时修改脚本,又或者开发引入了新的问题等等,自动化脚本通过率可能80%都不到。
用那个方法判断元素是否显示
is_displayed()
你曾经都写过多少自动化测试用例?
这个具体没有算过。但是只要有时间,模块稳定的功能都会写。就拿上个项目来说,自动化测试用例大概写了将近有100-120条这样子吧。
python3 的数据类型有哪些?
int (整型)
float (浮点型)
str(字符串)
List(列表)
Tuple(元组)
Set(集合)
Dictionary(字典)
不可变数据(四个):int (整型)、float (浮点型)、str(字符串)、Tuple(元组)、Set(集合);
可变数据(两个):List(列表)、Dictionary(字典)。
面:unittest框架了解吗?
参考答案:unittest框架,由setUp()–环境预置,testCase()— 测试用例 tearDown()----环境恢复,三大部分组成,unittest框架可组织执行测试用例,并且提供丰富的断言方法,判断测试用例是否通过,最终生成测试结果。
怎样用python连接mysql数据。
参考答案:我们之前主要是用python语言来写web端的自动化测试脚本,连接数据库的话,我们主要使用pymysql这个模块来进行连接的。一般在进行完自动化测试之后,我们会连接上数据库,将数据进行清除
用python做过接口测试自动化测试吗?
参考答案:我们之前主要是用python语言来写web端的自动化测试脚,接口是用Jmeter来做的,用python写接口的脚本也在网上学习过,主要使用到requests模块,但是工作中没用用过,到时候工作需要的话,再学一下应该没问题。
元素定位失败的原因
自动化脚本,如何切换不同的浏览器
参考答案:使用对应的浏览器驱动,然后在脚本中更换不同的浏览器。
你的python水平很一般啊?(遇到这种否定你的问题,一定不能虚!)
参考答案:我现在掌握的python知识,做ui层的自动化测试是可以的,代码的封装,调用这些都没问题;我一般是会做,但不是很会用文字描述出来,我以注意到这点,现在也在加强提升自己的总结能力。
PS—重点强调:凡是遇到被面试官否定的,都要想办法怼回去,输也要输得精彩些,但是,怼回去的时候,要注意语气,要有礼有节,不卑不亢。
python怎么定义一个函数,怎么定义一个类
def 函数名:
函数体
class 类名:
属性
方法
有些元素,在谷歌浏览器上能定位,在火狐浏览器上定位失败,是什么原因呢?
参考答案:因为不同浏览器的内核不一样,他们的CSS样式不一样。
如何提高selenium脚本的执行速度?
元素定位的方式有哪些
d.find_element_by_id('id的值')
d.find_element_by_name('name的值')
d.find_element_by_class_name('class的值')
d.find_element_by_tag_name('标签名')
d.find_element_by_link_text('完整的文本链接')
d.find_element_by_partial_link_text('部分的文本链接')
d.find_element_by_css_selector('css表达式')
d.find_element_by_xpath('xpath表达式')
js定位
如何切换iframe
switch_to.frame()
如何切换窗口
switch_to.window()
鼠标悬停的方法是什么
鼠标悬停用到ActionChains
类提供的move_to_element
方法
如何定位下拉框
需要导入Select
类,可以使用下标、值和文本定位
如何获取弹出警告框的text
switch_to.alert.text
什么样的项目适合做自动化
项目周期长,版本多,界面元素稳定的项目
selenium如何做兼容性测试
使用对应的浏览器驱动,然后在脚本中更换不同的浏览器。
为什么会生成HTML报告
使用了HTMLTestRunner第三方工具包来实现的
脚本运行出错,应该怎样定位,说出分析过程
运行结束之后我们会得到一个测试报告,我们根据测试报告先定位一下是脚本的原因还是程序的原因,一般来说脚本的原因在报告中都会显示出哪一行代码出错了,如果是程序的原因通常来说都是断言的问题。
如果系统有验证码,怎么做自动化?
setUp(),tearDown()和setUpClass(),tearDownClass()的区别:
参考答案:当测试用例有多个,setUp()和tearDown()就会被执行多次;不管测试用例有多少个,setUpClass()和tearDownClass()只会被执行一次。
python的第三方模块/标准库有哪些?
time,random,unittest,selenium,HTMLTestRunner
python的pass语句的作用是什么?
参考答案:占位符,当方法没有内容时,防止出现语法错误。
自动化写过哪些模块的脚本?
参考答案:主要是把冒烟测试的用例转化为脚本,比如,我这个xx商城系统,做自动化的模块有后台的上架商品,订单查询,添加团购活动,促销活动,前台的搜索商品,添加商品到购物车,下单等等。
元素的属性值是动态变化的,怎么定位这个元素?
参考答案:如果元素有属性值是动态变化的,我们就不要使用这个属性进行定位;我们可以使用这个元素的非动态变化,并且是唯一的值属性进行定位;也可以使用xpath或者css,使用层次+属性的方式定位。
webdriver的原理是什么?
参考答案:浏览器的驱动,接收客户端发过来的指令(指令就是我们的脚本),浏览器的驱动根据接收到的指令,驱动浏览器工作。
你们是怎么检查自动化的结果是不是正确的?
参考答案:我们会用unittest单元测试框架提供的断言方式来检查实际结果和预期结果是否一致,常用的断言方式有assertEqual(),assertIn(),还有一些其他的,不常用就没记了。
怎么样提升自动化脚本成功率
run_all_case中有哪些内容?
run_all_case具体的内容不太记得了,一般都是直接使用的,一般需要修改的是测试报告的路径,测试用例的路径,还有用例的匹配规则。
自动化的优点和缺点?
自动化的优点的话,可以提升测试的效率,比如我们之前是将冒烟测试的用例转换成自动化用例。可以节省自己的测试时间。
缺点的话,可能他的执行速度比较慢,其次他对于测试人员的代码能力需要一定要求。
unittest单元测试怎么安装的?
参考答案:不需要安装,是python自带的,直接通过import 关键字引用就可以了。
pytest了解吗?
参考答案:也是python的一个单元测试框架,它的用法比unittest框架复杂些。自动化测试我们一般是基于unittest框架来做的,pytest用的少,以后工作需要,我业余时间学习一下,很快上手。
po(page object:页面对象)设计模式了解吗?
参考答案:po还是了解的。po是web自动化测试目前最佳的一种实践方式,简单来说就是类和类之间的封装和调用。
包括基础类、页面类、用例层等部分。目前正在往这个方面进阶脚本。
在SVN中07_测试执行\禅道\安装包
可以查看到禅道安装包
将xampp-win32-1.7.7-VC9.zip复制到C盘
注意:必须是C盘的根目录下
直接右键,解压到当前文件夹
解压之后会得到一个xampp的文件夹
进入xampp文件夹中的htdocs文件夹
如下是我的路径,仅供参考
C:\xampp\htdocs
将安装包文件夹中的ZenTaoPMS.8.0.1.zip复制进来
复制进来之后,跟之前一样,解压到当前文件夹
解压完成后,回到上级目录,也就是xampp目录
然后拉倒最下面
双击xampp-control.exe文件
依次点击这两个start(apache和mysql的)
注意:依次点击,先等前一个running,再点击下一个
至此搭建完成,接下来就是禅道的安装了
打开浏览器输入网址
http://localhost/zentaopms/www/
开始安装
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jEj0XtZp-1617696547036)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230165903675.png)]
一直下一步,
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TUTeTjvF-1617696547037)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230165914191.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Kb8RjDZi-1617696547039)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230165934119.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SenD1jM9-1617696547039)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230165951049.png)]
使用管理员账号可以去创建产品、添加人员等等
进入产品
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QbRkWFDK-1617696547040)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230170107589.png)]
添加产品
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tfCnNygH-1617696547041)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230170119352.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AyiagD9s-1617696547042)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230170138466.png)]
切换所负责的产品
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sXUvCXMj-1617696547043)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230170151492.png)]
切换到需要添加模块的产品,点击维护模块
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dnqOSUYa-1617696547043)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230170203405.png)]
添加模块
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZqKROGOC-1617696547045)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230170215631.png)]
添加子模块
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VKupqBx7-1617696547046)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230170229638.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pLDCitNx-1617696547046)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230170243990.png)]
进入添加用户
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UV0ZQV0l-1617696547047)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230170301123.png)]
添加一个用户
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VPa31kKH-1617696547048)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230170312163.png)]
进入Python官网
根据操作系统进行下载选择
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dyAm1XvK-1617696547049)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230170514085.png)]
根据 自己电脑位数下载64位和32位
下载后会得到python-3.7.4-amd.exe
双击该文件进行安装
点击customize installation
直接next
选择advanced options
,前五项勾选并且改路劲
然后点击install
进行安装
找到Python安装目录
在开始处输入idle
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-75uHcdSq-1617696547049)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230170748681.png)]
鼠标右键 打开文件位置
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-l7iKdoG0-1617696547050)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230170802641.png)]
检查Python的环境变量
在dos界面输入命令python -V
注意V需要大写
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8LONgDqt-1617696547050)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230170824258.png)]
注意如果提示Python不是内部或外部命令也不是可运行的程序则需要添加环境变量至Path
先找到Python的安装目录,在dos界面输入如下命令
setx "Path" "Python的安装目录;%Path%;" /m
比如我的Python安装在C:\Python中,那么我的命令则是
setx "Path" "C:\Python;%Path%;" /m
执行Python代码
输出/打印内容 print()
print('李四')
print(5)
print默认是以\n换行为结尾
如果需要修改print的结束符,在print最后增加,end=‘以什么结尾’
print(需要输出的内容,end=’’)
print('hello',end='>>>>>>>>>')
print('world',end='\t')
print('python',end='<<<<<<<<<<<<')
数据类型
在Python3中基本的数据类型有三个
字符串使用引号引起来
注意一下必须是用成对成对的引号引起来,也就是以什么引号开头,就要以什么引号结尾。
'张三'
"张三"
'''张三'''
"""张三"""
str() 转换成字符串 int()转换成整型 float()转换成浮点型
a = '5.6'
a = int(a)
print(type(a))
print(a)
字符串常用方法
lenth = len(a)
print(lenth)
a = '[email protected]'
# 切割字符串,将字符串切割成列表
qqnum = a.split('@')
print(qqnum)
a ='hello,world'
a.count('o')
bingo = a[3]
print(bingo)
b = 'hello,'
c = b+a
print(c)
print(a*5)
name = '李四'
age = 18
nation = '汉族'
location = '深圳市'
msg = '你好,我是{0},我今年{1}岁,我是{2}人,来自{3}'.format(name,age,nation,location)
print(msg)
\n >>> 换行 \t >>> tab键
# 如果我想打印出来的是"随便打\n印一\t行字符串"
print('随便打\\n印一\\t行字符串')
print(R'随便打\n印一\t行字符串')
a = 'world'
result = 'or' in a
# result1 = 'o' in a or 'asdb' in a
result1 = 'o' in a and 'asdb' in a
print(result1)
变量
在Python定义变量其实就是给一个值取一个名字,或者给某一个变量赋值
name='张三'
讲变量之前,我们先来看一看这一段代码,这个代码的意思就是说把张三这个字符串给到了name,把一个值(张三)赋值给一个名字(name)。变量名就像我们现实社会的名字,把一个值赋值给一个名字时,称之为变量(variable),在大多数语言中,都把这种行为称为“给变量赋值”或“把值存储在变量中”。
定义变量使用=定义,=左边的是变量名,=右边的是变量的值
变量名=变量值
del
a = 15
del a
a = 15
b = 1.5
c = '1.5'
print(type(a))
print(type(b))
print(type(c))
a = b = c = 5
print(a)
print(b)
print(c)
a,b,c = 3,4,7
print(a)
print(b)
print(c)
算术运算(只能够用在数字与数字之间)
+
-
*
/
//
%
**
print(b+c)#加法
print(b-c)#减法
print(b*c)#乘法
print(b/c) #除法
print(b//c)#地板除 求整数部分
print(b%c)#求余数的部分
print(b**c)#幂运算 b的c次方
input() 接受用户的输入
name = input('请输入您的姓名:')
print('您输入的是{0}'.format(name))
常见比较操作符
符号 | 含义 |
---|---|
== | 相等/等于 |
<= | 小于等于 |
>= | 大于等于 |
< | 小于号 |
> | 大于号 |
!= | 不等于 |
if…else语句
在冒号后:下一行后带有缩进,缩进是Python核心,Python就是通过缩进来控制代码的。
缩进(一个tab/四个空格) 不可以混着用.。
假设 用户名 为admin,密码为 admin123,写一个程序判断用户是否登录成功
username = input('请输入用户名')
password = input('请输入密码')
if username == 'admin' and password == 'admin123':
print('登录成功')
print('正在进入程序。。。。')
else:
print('用户名或密码错误')
print('登录失败')
那如果有多个条件需要判断,则需要使用elif语句
语法:
if 条件1:
条件1成立时执行
elif 条件2:
条件2成立时执行
elif 条件3:
条件3成立时执行
elif 条件4:
条件4成立时执行
else:
所有条件都不成立,才执行
比如:根据分数判断等级
81 - 100 >>>> A
60 - 80 >>>> B
40 - 59 >>>> C
0 - 39 >>>> D
不在0-100 之间 >>> 输入错误
score = int(input('请输入分数'))
if 81 <= score <= 100:
print('A')
elif 60 <= score <=80:
print('B')
elif 40 <= score <=59:
print('C')
elif 0 <= score <=39:
print('D')
else:
print('输入错误')
循环
语法:
while 条件:
循环内容
# 定义次数为3
times = 3
while times > 0:
print('当条件成立时')
print('执行while循环')
print('每一次循环结束的时候,会再一次检查条件是否成立')
times = times - 1
优化猜数字游戏
num = 8
# 定义次数为3
times = 3
while times > 0:
guess = int(input('请输入1-10之间的整数'))
if guess == num:
print('猜对了')
times = -999
elif guess > num:
print('大了')
else:
print('小了')
times = times - 1
1+2+3+4+…100的和
# 定义和等于0
sums = 0
num = 1 # 从1开始加
while num <=100:
sums = sums + num
num = num +1
print(sums)
index = 1
while index < 10:
print(index)
if index == 5:
print('执行continue语句')
continue
index = index + 1
print('>>>>>>>>>>>>>>>>>>>>>>>>>')
index = 1
while index < 10:
print(index)
if index == 5:
print('执行break语句')
break
index = index + 1
print('>>>>>>>>>>>>>>>>>>>>>>>>>')
结合break与continue优化猜数字游戏
num = 8
# 定义次数为3
times = 3
while times > 0:
guess = int(input('请输入1-10之间的整数'))
if guess < 1 or guess > 10:
print('输入错误')
continue
elif guess == num:
print('猜对了')
break
elif guess > num:
print('大了')
else:
print('小了')
times = times - 1
异常处理
try:
print('这是try语句的内容')
int('aaaa')
print('try语句报错,就直接跳转执行except语句')
except:
print('这是except语句的内容')
print('只要当try语句中的内容报错了')
print('才会执行except语句')
try:
num = float(input('请输入一个小数'))
num2 = int(num+0.5)
print('您输入的是{0},四舍五入后为{1}'.format(num,num2))
except:
print('输入错误')
词典(键值对)
一个键(key)对应一个值(value),是一个一一对应的数据类型
词典用{}表示,词典中的每一对用,分隔开。键与值之间用:对应
key/键是唯一的
a = {'中国移动':10086,'中国联通':10010,'中国电信':10000}
print(a['中国移动'])# 如果读取的key不存在,会报错
print(a.get('中国移动'))# 如果读取的key不存在,则返回None
result = '中国移动' in a
print(result)
result2 = 'aaaa' in a
print(result2)
a['中国移动'] = '12345'
print(a)
a['中国铁通'] = '不知道'
print(a)
del a['中国铁通']
print(a)
print(a.keys())
print(a.values())
print(a.items())
for循环
for 循环是根据目标的元素个数来决定循环的次数
语法如下:
for 变量 in 目标:
循环内容
目标有多少个元素,就循环多少次
a = ['python','java','php']
for i in a:
print(i)
print('for循环,每一次循环会找到目标的一个元素')
print('并且赋值个变量,直到所有的元素都找完')
通常配合for循环一起使用的就是range()函数
range()三种用法
range(10) # 表示生成0,1,2,3,4,5,6,7,8,9
range(1,10) # 表示生成1,2,3,4,5,6,7,8,9
range(1,10,2) # 表示生成1,3,5,7,9
一筐球 红色有6个, 黄色有3个,每次随机拿4个球
for red in range(1,5):
for yellow in range(4):
if red+yellow == 4:
print('红球有{0}个,黄球有{1}个'.format(red,yellow))
列表
在其他编程语言中有的称之为数组,列表是python仓库,他可以存放所有的数据。列表用[]表示,列表中的每一项用,分隔开
a = [3,3.14,'world',5]
print(len(a))
print(a[2])
del a[1]
print(a)
a[2] = 'hello'
print(a)
a.append('python')# 将python增加到列表a的尾部,一次只能增加一个元素
a.reverse()
print(a)
a.sort()
print(a)
b = sorted(a)
print(a)
print(b)
a = [5,2,3,1,7,9,8,11,12,13,111,23,345]
a[::-1]
元组
元组是一个不可变的列,用()表示,每一项用,分隔开
a = (1,2,3,1,23)
a = (2,)
访问元组元素的方法,与列表一样,通过下标访问,大部分的方法例如切片等等都可以使用
a = (1,2,3,1,23)
print(a[2])
集合
集合 {} 里面的每一项用,分隔开
集合里面的元素是唯一的
c = {3,4,3,4,1,2,3,4,12,3,4,5}
print(c)
c = {1,2,1,2,3,54,2}
c.add(5)# 增加一个元素
c.update([1,2,3,4,5,6,11,12,13,14,15])#增加多个元素
print(c)
函数
什么是函数呢?数学上的函数,是指给定一个输入,就会有唯一输出的一种对应关系。编程语言里的函数跟这个意思差不多,但也有不同。就是你编写了一些语句,为了方便使用这些语句,把这些语句组合在一起,给它起一个名字。使用的时候只要调用这个名字,就可以实现语句组的功能了。它有可能需要输入,有可能会返回输出。
def 函数名称():
函数实现过程
函数实现过程
比如创建一个hello函数
def hello():
print('这是我创建的第一个函数')
print('一个叫做hello的函数')
print('我现在有些激动')
print('函数只要被调用才会执行')
注意,函数只有调用才会执行
hello()#调用函数
def add(num1,num2):
print('第一个参数是:{0}'.format(num1))
print('第二个参数是:{0}'.format(num2))
有参数的函数,在调用时,一定要传递参数
add(5,16)# 顺序传参
add(num2=15,num1=7)# 关键字传参
def login(username,password):
if username =='admin' and password =='admin123':
return '登录成功'
else:
return '登录失败'
result = login('admin','admin123')
print(result)
类
相信我们之前百度也好通过其他途径也好,应该都听说过Python是一个面向对象的语言,python处处都是对象,但是我们并不知道什么是对象。简单的来说对象=属性+方法,打个比方,把一个人当做对象,我们就可以从这两个方面去描述这个人。
在Python中的对象也是如此,如果把计算器写成代码会是如下情况:
class calc():
name='超级计算器'
def add(self,a,b):
print(a+b)
看到这个代码没,这个代码就是定义了对象的属性和方法,我们将这个定义的过程叫做类(class)。就叫做类的实例对象也叫实例。
我们需要使用类来创建一个真正的对象,而这个对象
说到这里,如果大家还是不明白,你可以这样想我们造房子需要图纸,但是仅仅有个图纸你也住不进去啊,图纸只告诉我们房子长成什么样子,但图纸不是真正的房子,我们需要根据图纸真金白银的造房子才能住进去。另外我们根据图纸是可以造出很多房子来的。这就跟我们的类一样,类就像我们的图纸,而我们创建的类的实例,就是一个又一个的房子。
对象
好了说了这么多,创建一个对象,也叫类的实例化其实so easy
tt = calc()#这样就创建了calc类的实例化
注意类名后面带着(),如果需要调用对象的方法,使用点操作符(.)即可
tt = calc()
tt.add(5,2)
self是什么?
我们应该发现了,每一个方法下都会有一个self参数,self到底是什么呢?如果我们之前把类比作图纸,那么由类实例化后的对象才是真正可以住人的房子,我们可以根据图纸建造成千上万的房子,但是每一个房子都有各自的主人,self这里就相当于门牌号,有了self,每个主人才能正确的进入自己的房子
切记:所有方法的第一个参数必须是self,但是使用时,无需传参!
我们需要注意的东西:
• 类(Class): 用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。
• 类变量:定义在类中的变量,我们叫做类变量
• 实例化:创建一个类的实例,类的具体对象。
• 方法:类中定义的函数。
• 对象:通过类定义的数据结构实例。对象包括两个数据成员(类变量和实例变量)和方法。
单继承
比如我现在实现一个会员等级功能
class vip1():
name = '初级VIP'
def download(self):
print('下载速度提升10%')
现在我想增加一个vip2的等级,要求拥有VIP1的所有特权外,上传速度还能提升10%
这个时候我们可以用到继承
class类名(被继承的类):
pass#pass为占位符,表示什么都不做
class vip2(vip1):
def upload(self):
print('上传速度提升10%')
被继承的类我们称之为父类,继承者我们叫做子类,一个子类可以继承父类的全部属性和方法。
我们可以对继承过来的方法与变量进行重新定义。
class vip3(vip2):
name = '高级VIP'
def download(self):
print('下载速度提升20%')
Python自带了功能丰富的标准库,另外还有数量庞大的各种第三方库。使用这些功能的基本方法就是使用模块,通过模块,可以重用别的程序中的代码。模块可以理解为是一个包含了函数和变量的py文件。在你的程序中引入了某个模块,就可以使用其中的函数和变量。
time模块
time模块提供了很多方法,先来看这两个
import time
start_time = time.time()
time.sleep(5)
end_time = time.time()
print('开始时间为{0}'.format(start_time))
print('结束时间为{0}'.format(end_time))
random模块同样也有很多方法,先看这两个
import random
bingo = random.randint(1,10)
print(bingo)
a =['小米','华为','OPPO','vivo']
bingo2 = random.choice(a)
print(bingo2)
安装
pymysql 是在 Python3.x 版本中用于连接 MySQL 服务器的一个库,Python2中则使用mysqldb。
因此在操作数据库前安装pymysql
第三方库
在dos界面输入命令python -m pip install pymysql
数据库信息
演示数据库如下:
名称 | 内容 |
---|---|
数据库ip | 120.77.212.195 |
端口 | 3306 |
数据库名称 | brtctest |
用户名 | admin |
密码 | admin123 |
表名stu
字段如下
字段 | 含义 | 约束 |
---|---|---|
id | 学员id | number,主键 |
name | 学员姓名 | varchar |
age | 学员年龄 | number |
nation | 学员民族 | varchar,默认汉族 |
数据库操作
import pymysql
# 打开数据库连接
db = pymysql.connect("数据库IP","用户名","密码","连接的数据库",数据库端口)
# 使用cursor()方法获取操作游标
cursor = db.cursor()
# SQL 插入语句
sql = "需要执行的sql语句"
# 执行sql语句
cursor.execute(sql)
# 提交变动的数据
db.commit()
# 回滚变动的数据
db.rollback()
# 关闭数据库连接
db.close()
查询数据与之前的增删改无任何太大的区别,主要有如下区别:
主要用到如下方法:
方法 | 作用 |
---|---|
fetchone() | 获取一条结果 |
cursor.fetchall() | 获取所有结果 |
cursor.rowcount | 获取结果有多少条 |
# 操作mysql数据库,需要导入pymysql
import pymysql
# 先连接数据库
# pymysql.connect(数据库ip地址,用户名,密码,数据库名称,端口)
db =pymysql.connect('120.77.212.195','admin','admin123','brtctest',3306)
# 创建数据库操作游标
cs = db.cursor()
sql = "select * from stu"
执行sql语句
cs.execute(sql)
# 通过rowcount 计算出查询了多少条数据
all_line = cs.rowcount
print(all_line)
# 读取全部查询结果
result = cs.fetchall()
for i in result:
print(i)
读取下一条数据
one = cs.fetchone()
two = cs.fetchone()
three = cs.fetchone()
print(one)
print(two)
print(three)
db.close()
python 做接口测试
用到模块 requests
安装模块 python -m pip install requests
https://github.com/requests/requests
python setup.py install
即可。requests发送请求
方法 | 解释 |
---|---|
requests.get() | 获取html的主要方法 |
requests.post() | 向html网页提交post请求的方法 |
requests.delete() | 向html提交删除请求 |
requests.put() | 向html网页提交put请求的方法 |
requests.head() | 获取html头部信息的主要方法 |
requests.patch() | 向html提交局部修改的请求 |
import requests
r = requests.get(url)#发送get请求
r = requests.post(url)#发送post请求
# 其余请求的发送方式一样,故不再演示
在发送请求时,除了url之外,还有许多参数,一一来看
url
url,请求的路径,表示这个请求发送到哪里去
import requests
myurl = 'http://brtc.imsam.cn'
r = requests.get(url=myurl)
params
跟url一起发送的参数(以字典方式传递),通常使用在get请求中
import requests
myurl = 'http://brtc.imsam.cn'
kv = {'username':'张三','age':'18'}
r = requests.get(url=myurl,params=kv)
data
字典,与params不同的是,data提交的数据并不放在url链接里,通常在post请求中使用
import requests
myurl = 'http://brtc.imsam.cn'
kv = {'username':'张三','age':'18'}
r = requests.post(url=myurl,data=kv)
json
以json的方式发送请求数据,通常也用在post请求中
import requests
myurl = 'http://brtc.imsam.cn'
kv = {'username':'张三','age':'18'}
r = requests.post(url=myurl,json=kv)
headers
定制请求的头部信息
import requests
myurl = 'http://brtc.imsam.cn'
kv = {'username':'张三','age':'18'}
hd ={"User-Agent":" Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36"}
r = requests.get(url=myurl,params=kv,headers=hd)
files
发送带文件的请求
import requests
myurl = 'http://brtc.imsam.cn'
upfile = {'file': open('文件路径', 'rb')}
r = requests.post(url=myurl,files=upfile)
timeout
设置超时时间
import requests
myurl = 'http://brtc.imsam.cn'
kv = {'username':'张三','age':'18'}
r = requests.post(url=myurl,data=kv,timeout=0.01)
proxies
设置访问代理
import requests
myurl = 'http://brtc.imsam.cn'
kv = {'username':'张三','age':'18'}
proxy = {"http": "http://10.10.1.10:3128","https": "https://10.10.1.100:4444"}
r = requests.post(url=myurl,data=kv,proxies=proxy)
如果代理需要用户名和密码,则需要这样:
import requests
myurl = 'http://brtc.imsam.cn'
kv = {'username':'张三','age':'18'}
proxy = {"http": "http://用户名:密码@10.10.1.10:3128","https": "https://用户名:密码10.10.1.100:4444"}
r = requests.post(url=myurl,data=kv,proxies=proxy)
自动带上cookie
s = requests.Session()
r = s.get('url')
响应内容
import requests
myurl = 'http://brtc.imsam.cn'
kv = {'username':'张三','age':'18'}
r = requests.post(url=myurl,data=kv)
r.text# 以字符串方式返回响应内容
# 更多响应内容如下
响应 | 含义 |
---|---|
r.encoding | #获取当前的编码 |
r.encoding = ‘utf-8’ | #设置编码 |
r.text | #以encoding解析返回内容。字符串方式的响应体,会自动根据响应头部的字符编码进行解码。 |
r.content | #以字节形式(二进制)返回。字节方式的响应体,会自动为你解码 gzip 和 deflate 压缩。 |
r.headers | #以字典对象存储服务器响应头,但是这个字典比较特殊,字典键不区分大小写,若键不存在则返回None |
r.status_code | #响应状态码 |
r.json() | #Requests中内置的JSON解码器,以json形式返回,前提返回的内容确保是json格式的,不然解析出错会抛异常 |
r.raise_for_status() | #失败请求(非200响应)抛出异常 |
用于加密相关的操作,主要提供 SHA1, SHA224, SHA256, SHA384, SHA512 ,MD5 算法
不同算法的使用语法都是一样的。
import hashlib
m = hashlib.md5()
m.update("123456".encode('utf-8'))
print(m.digest()) #2进制格式hash
print(m.hexdigest()) #16进制格式hash
import hashlib
# md5 加密展示
hash = hashlib.md5()
hash.update('123456'.encode('utf-8'))
print(hash.hexdigest())
# sha1 加密展示
hash = hashlib.sha1()
hash.update('123456'.encode('utf-8'))
print(hash.hexdigest())
# sha256 加密展示
hash = hashlib.sha256()
hash.update('123456'.encode('utf-8'))
print(hash.hexdigest())
# sha384 加密展示
hash = hashlib.sha384()
hash.update('123456'.encode('utf-8'))
print(hash.hexdigest())
# sha512 加密展示
hash = hashlib.sha512()
hash.update('123456'.encode('utf-8'))
print(hash.hexdigest())
安装selenium
selenium对于Python而言是一个第三方的模块
Python安装第三方模块在dos界面输入命令
python -m pip install 模块名称
比如安装selenium,那么输入命令
python -m pip install selenium
看到如下字眼则表示安装成功
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gbhgW5GX-1617696547053)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230171307750.png)]
安装浏览器(Chrome)
进入官网安装
安装相对应的浏览器驱动(driver)
先查看自己安装的浏览器的版本
直接在chrome浏览器地址栏粘贴chrome://version/
即可查看到版本
下载跟浏览器版本对应的驱动
国内淘宝镜像地址
点击选择跟自己版本的对应的连接
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-G2ARoMYL-1617696547054)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230171319612.png)]
点击下载
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-on5OxpCa-1617696547055)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230171331969.png)]
下载后,解压到当前目录
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-u561v47I-1617696547056)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230171343973.png)]
得到chromedriver.exe
文件
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MzrEwmPF-1617696547056)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230171355198.png)]
进入到Python安装目录
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ccNTmIw0-1617696547057)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230171408161.png)]
右键打开文件位置
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-M86SD7CN-1617696547057)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230171422990.png)]
将这个exe文件放到Python安装目录
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Wv3Q0foD-1617696547058)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230171433410.png)]
检查一下是否安装成功
新建一个Python文件,执行下面脚本,看是否能打开。
selenium.py
from selenium import webdriver
from time import sleep
#打开谷歌浏览器,并且赋值给变量d
d = webdriver.Chrome()
d.maximize_window()# 最大化窗口
# 通过get() 打开一个网址
d.get('https://www.baidu.com')
sleep(5)
# 关闭当前窗口
d.close()
# 关闭所有窗口,并且关闭驱动
d.quit()
在进行web自动化之前,需要先来了解一下web页面的基本内容。
比如,如下是一张百度首页
那如果我们需要对百度页面进行操作,那么我们就需要知道他的html代码了。
我们可以鼠标选中需要操作的元素,鼠标右键,检查
来看看这行代码
首先第一个,这个是一个html代码,那html代码中 这个代码我们称之为input标签
那在这个input标签中,有很多的属性,其中=
左边的是属性名称,=
右边的是属性值
所以这个html标签有id、name、class、value、maxlength等等属性
第二个,HTML标签有自己的层级关系
如图,span标签就是input标签的父标签
定位方式 | 定位表达式 |
---|---|
根据id来定位 | d.find_element_by_id(‘id的值’) |
根据name来定位 | d.find_element_by_name(‘name的值’) |
根据class来定位 | d.find_element_by_class_name(‘class的值’) |
根据标签名定位 | d.find_element_by_tag_name(‘标签名’) |
根据文本链接定位 | d.find_element_by_link_text(‘完整的文本链接’) |
根据部分文本链接定位 | d.find_element_by_partial_link_text(‘部分的文本链接’) |
根据css选择器定位 | d.find_element_by_css_selector(‘css表达式’) |
根据xpath定位 | d.find_element_by_xpath(‘xpath表达式’) |
Xpath定位
/html/body/div/form/p/label/input
/html/body/div/form/p[2]/label/input
//标签名[@属性名="属性值"]
比如说:想定位到 for=“user_pass” 的label标签
//label[@for="user_pass"]
//标签名[@属性名="属性值"][@属性名="属性值"]
//input[@class="input"][@id="user_pass"]
比如:定位到 for=“user_pass” 的label标签 的 input子标签
//label[@for="user_pass"]/input
使用Xpath实现登录blog
from selenium import webdriver
from time import sleep
d = webdriver.Chrome()
d.get('http://os-201804081018/blog/wp-login.php')
d.maximize_window()
sleep(3)
d.find_element_by_xpath('//label[@for="user_login"]/input').send_keys('test')
sleep(1)
d.find_element_by_xpath('/html/body/div/form/p[2]/label/input').send_keys('test123')
sleep(1)
d.find_element_by_xpath('//input[@class="button button-primary button-large"]').submit()
sleep(1)
d.close()
d.quit()
CSS定位
标签名[属性名="属性值"]
比如说:想定位到 for=“user_pass” 的label标签
label[for="user_pass"]
input[class="input"][id="user_pass"]
比如:定位到 for=“user_pass” 的label标签 的 input子标签
label[for="user_pass"] input
[for="user_pass"]
想定位到:id=“user_pass” 的 input标签
input#user_pass
想定位到:class=“button-primary” 的input标签
input.button-primary
想定位到:class=“button-primary” id=“wp-submit” 的input标签
input.button-primary#wp-submit
使用css定位实现blog登录
from selenium import webdriver
from time import sleep
d = webdriver.Chrome()
d.get('http://os-201804081018/blog/wp-login.php')
d.maximize_window()
sleep(3)
d.find_element_by_css_selector('#user_login').send_keys('test')
sleep(3)
d.find_element_by_css_selector('input[type="password"]').send_keys('test123')
sleep(3)
d.find_element_by_css_selector('p.submit input#wp-submit').click()
sleep(3)
d.close()
d.quit()
test
test123
from selenium import webdriver
from time import sleep
# 打开谷歌浏览器,并且赋值给变量d
d = webdriver.Chrome()
# 最大化窗口
d.maximize_window()
sleep(2)
# 通过get()方法,在当前窗口打开网页
d.get('http://www.baidu.com')
sleep(2)
d.get('http://www.taobao.com')
sleep(2)
d.close()#关闭当前窗口
d.quit()#关闭所有窗口,并且退出驱动
点击 click()
输入内容 send_keys()
清空输入的内容 clear()
from selenium import webdriver
from time import sleep
# 打开谷歌浏览器,并且赋值给变量d
d = webdriver.Chrome()
# 最大化窗口
d.maximize_window()
d.get('https://www.so.com/')
sleep(1)
# 定位到输入框,输入Python
d.find_element_by_css_selector('#input').send_keys('Python')
sleep(1)
# 清空输入的内容
d.find_element_by_css_selector('#input').clear()
sleep(1)
# 重新输入Selenium
d.find_element_by_css_selector('#input').send_keys('Selenium')
sleep(1)
# 点击搜索按钮
d.find_element_by_css_selector('#search-button').click()
sleep(1)
d.close()#关闭当前窗口
d.quit()#关闭所有窗口,并且退出驱动
is_displayed() 判断元素是否显示/可见
如果元素可见,则返回True,否则返回False
注意 :不管元素是否可见,我们都是可以定位到的。只是不可见的元素,我们是无法进行操作。
隐藏元素属性 |
---|
type=“hidden” |
style=“display:none” |
from selenium import webdriver
from time import sleep
# 打开谷歌浏览器,并且赋值给变量d
d = webdriver.Chrome()
# 最大化窗口
d.maximize_window()
d.get('http://shop.imsam.cn/wp-login.php')
# 判断元素是否可见,如果可见,则返回True
res = d.find_element_by_css_selector('#wp-submit').is_displayed()
print(res)
res2 = d.find_element_by_css_selector('[name="testcookie"]').is_displayed()
print(res2)
# 隐藏元素是可以定位到的,只是无法操作
d.close()#关闭当前窗口
d.quit()#关闭所有窗口,并且退出驱动
text 返回元素的文本
get_attribute(“属性”) 获取属性对应值
隐式等待
implicitly_wait(n)
n为秒数
隐式等待,是通过一定的时长等待页面的某个元素加载完成。如果超出了设置的时长,元素还没有被加载出来,则抛出异常。
from selenium import webdriver
from time import sleep
# 打开谷歌浏览器,并且赋值给变量d
d = webdriver.Chrome()
# 最大化窗口
d.maximize_window()
# 隐式等待
d.implicitly_wait(10)# 最大等待10s
d.get('http://shop.imsam.cn/wp-login.php')
d.find_element_by_css_selector('#user_login').send_keys('admin')
d.find_element_by_css_selector('#wp-submit').click()
sleep(1)
# 获取元素文本属性
msg = d.find_element_by_css_selector('#login_error').text
print(msg)
# 获取属性对应值
value = d.find_element_by_css_selector('#user_pass').get_attribute('type')
print(value)
d.close()#关闭当前窗口
d.quit()#关闭所有窗口,并且退出驱动
鼠标悬停
使用该方法,首先要把ActionChains类导进来,引入ActionChains类的方法如下:
from selenium.webdriver import ActionChains
语法:
ActionChains(浏览器).move_to_element(需要悬停的元素).perform()
下拉框元素定位
需要先导包from selenium.webdriver.support.ui import Select
语法:
Select(下拉框元素定位).select_by_index(下标)#根据下标选择
Select(下拉框元素定位).select_by_visible_text('文本信息')#根据文本选择
Select(下拉框元素定位).select_by_value('value的值')# 根据value的值来选择
from selenium import webdriver
from time import sleep
#导入鼠标操作
from selenium.webdriver import ActionChains
# 针对Select标签下拉,导包
from selenium.webdriver.support.ui import Select
# 打开谷歌浏览器,并且赋值给变量d
d = webdriver.Chrome()
# 最大化窗口
d.maximize_window()
# 隐式等待
d.implicitly_wait(10)# 最大等待10s
d.get('https://www.baidu.com')
sleep(1)
# 鼠标悬停
# 先定位到需要悬停的元素
mte = d.find_element_by_link_text('设置')
sleep(1)
#语法:ActionChains(浏览器).move_to_element(需要悬停的元素).perform()
ActionChains(d).move_to_element(mte).perform()
sleep(1)
d.find_element_by_link_text('搜索设置').click()
sleep(2)
#下拉框元素定位(1)
# d.find_element_by_css_selector('#nr').click()#先点击下拉框
# sleep(1)
# d.find_element_by_css_selector('[value="20"]').click()#再点击选项
# 只针对select标签下拉框
# 先定位到下拉框
sel = d.find_element_by_css_selector('#nr')
# Select(要操作的下拉框).如何操作
# 根据文本选择
Select(sel).select_by_visible_text('每页显示50条')
sleep(1)
# 根据value来选择
Select(sel).select_by_value('10')
sleep(1)
# 根据下标选择(从0开始)
Select(sel).select_by_index(1)
sleep(1)
d.close()#关闭当前窗口
d.quit()#关闭所有窗口,并且退出驱动
send_keys() 上传文件
只针对input标签的上传文件
from selenium import webdriver
from time import sleep
# 打开谷歌浏览器,并且赋值给变量d
d = webdriver.Chrome()
# 最大化窗口
d.maximize_window()
sleep(1)
d.get('https://www.baidu.com/')
sleep(1)
# 定位到相机图标,进行点击
d.find_element_by_css_selector('.soutu-btn').click()
sleep(1)
# 定位到上传文件的按钮,通过send_keys()直接输入文件的路径即可上传
d.find_element_by_css_selector('.upload-pic').send_keys('D:\\360.png')
sleep(3)
d.close()
d.quit()
多表单切换
switch_to.default_content()
表单的嵌套通常是使用 frame
或者 iframe
标签实现的,因此需要先切换到该标签中。
from selenium import webdriver
from time import sleep
# 打开谷歌浏览器,并且赋值给变量d
d = webdriver.Chrome()
# 最大化窗口
d.maximize_window()
d.get('https://mail.qq.com/')
sleep(1)
# 表单嵌套 frame 标签 iframe标签
# (在一个网页中,嵌套了更多网页)
# 先定位到需要切换的表单
frame_ele = d.find_element_by_css_selector('#login_frame')
d.switch_to.frame(frame_ele)
sleep(1)
d.find_element_by_css_selector('#u').send_keys('123456789')
sleep(2)
# 返回到最外层表单
d.switch_to.default_content()
# # 返回到上一层表单
# d.switch_to.parent_frame()
d.find_element_by_link_text('基本版').click()
d.close()#关闭当前窗口
d.quit()#关闭所有窗口,并且退出驱动
警告框 alert
from selenium import webdriver
from time import sleep
from selenium.webdriver import ActionChains
# 打开谷歌浏览器,并且赋值给变量d
d = webdriver.Chrome()
# 最大化窗口
d.maximize_window()
d.implicitly_wait(10)# 最大等待10s
d.get('https://www.baidu.com')
sleep(1)
# 鼠标悬停
# 先定位到需要悬停的元素
mte = d.find_element_by_link_text('设置')
sleep(1)
#语法:ActionChains(浏览器).move_to_element(需要悬停的元素).perform()
ActionChains(d).move_to_element(mte).perform()
sleep(1)
d.find_element_by_link_text('搜索设置').click()
sleep(2)
d.find_element_by_link_text('保存设置').click()
sleep(1)
# 警告框操作
msg = d.switch_to.alert.text#获取警告框的文本
print(msg)
# d.switch_to.alert.accept()#确认/接收警告框
d.switch_to.alert.dismiss()#关闭/取消警告框
d.close()#关闭当前窗口
d.quit()#关闭所有窗口,并且退出驱动
多窗口处理
如果遇到多窗口处理,我们就要切换窗口了。
window_handles
获取所有窗口,以列表的形式返回
switch_to.window()
切换窗口
from selenium import webdriver
from time import sleep
# 打开谷歌浏览器,并且赋值给变量d
d = webdriver.Chrome()
# 最大化窗口
d.maximize_window()
d.get('https://www.jianshu.com/')
sleep(1)
d.find_element_by_css_selector('#q').send_keys('Python')
sleep(1)
d.find_element_by_css_selector('.ic-search').click()
sleep(1)
# 获取所有窗口,以列表的形式返回
all_windows = d.window_handles
# 切换窗口
d.switch_to.window(all_windows[1])
sleep(1)
d.find_element_by_css_selector('#q').clear()
d.close()#关闭当前窗口
d.quit()#关闭所有窗口,并且退出驱动
find_elements可以找到所有符合规则的元素,并且以列表的形式返回。
在selenium中执行JavaScript语句需要使用execute_script(js语句)
来执行
window.scrollTo(0,b);
其中b表示与顶部的距离
document.querySelector('CSS表达式').removeAttribute('需要移除的属性名称');
document.querySelectorAll('CSS表达式')[下标].removeAttribute('移除的属性名称');
隐藏元素属性 |
---|
type=“hidden” |
style=“display:none” |
只读属性 |
---|
readonly=“readonly” |
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EQEwBCwq-1617696547064)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230171618448.png)]
在前一次定位的基础上,在进行一次定位
语法: **`find_element_by_xxx().find_element_by_xxx()
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-N1NLyweq-1617696547065)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230171608070.png)]
简书实例
from selenium import webdriver
from time import sleep
d = webdriver.Chrome()
d.maximize_window()
d.get('https://www.jianshu.com/')
sleep(2)
all_user = d.find_elements_by_css_selector('.list li')
for i in all_user:
name = i.find_element_by_css_selector('.name').text
data = i.find_element_by_tag_name('p').text
print('作者:{0},{1}'.format(name,data))
sleep(0.5)
显示等待就是有条件的等待
隐式等待就是无条件的等待
隐式等待
当使用了隐式等待执行测试的时候,如果 WebDriver没有在 DOM中找到元素,将继续等待,超出设定时间后则抛出找不到元素的异常,
换句话说,当查找元素或元素并没有立即出现的时候,隐式等待将等待一段时间再查找 DOM,默认的时间是0、
from selenium import webdriver
browser = webdriver.Chrome()
browser.implicitly_wait(10)#等待十秒加载不出来就会抛出异常,10秒内加载出来正常返回
browser.get('[https://www.zhihu.com/explore](https://www.zhihu.com/explore)')
input = browser.find_element_by_class_name('zu-top-add-question')
print(input)
显式等待
指定一个等待条件,和一个最长等待时间,程序会判断在等待时间内条件是否满足,如果满足则返回,如果不满足会继续等待,超过时间就会抛出异常
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
browser = webdriver.Chrome()
browser.get('https://www.taobao.com/')
wait = WebDriverWait(browser, 10)
input = wait.until(EC.presence_of_element_located((By.ID, 'q')))
button = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, '.btn-search')))
print(input, button)
title_is 标题是某内容
title_contains 标题包含某内容
presence_of_element_located 元素加载出,传入定位元组,如(By.ID, 'p')
visibility_of_element_located 元素可见,传入定位元组
visibility_of 可见,传入元素对象
presence_of_all_elements_located 所有元素加载出
text_to_be_present_in_element 某个元素文本包含某文字
text_to_be_present_in_element_value 某个元素值包含某文字
frame_to_be_available_and_switch_to_it frame加载并切换
invisibility_of_element_located 元素不可见
element_to_be_clickable 元素可点击
staleness_of 判断一个元素是否仍在DOM,可判断页面是否已经刷新
element_to_be_selected 元素可选择,传元素对象
element_located_to_be_selected 元素可选择,传入定位元组
element_selection_state_to_be 传入元素对象以及状态,相等返回True,否则返回False
element_located_selection_state_to_be 传入定位元组以及状态,相等返回True,否则返回False
alert_is_present 是否出现Alert
创建一个文件夹存放整个项目自动化内容
比如:我在G盘创建了一个 blog_project
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-B6o9vaiu-1617696547066)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230171904698.png)]
然后在该文件夹下再创建两个文件夹 testcase
与 **`report
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hi8Wgn8Q-1617696547067)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230171914458.png)]
在 testcase
文件夹下完成以下内容
login_case.py
文件user_case.py
文件编写以下几条测试用例
(只需要输入用户名与邮件)
reg_case.py
文件编写以下几条测试用例
post_case.py
文件进入到文章-所有文章页面,编写以下几条测试用例
给两条示例:
from selenium import webdriver
from time import sleep
# 登录成功
d = webdriver.Chrome()
d.maximize_window()
d.implicitly_wait(10)
d.get('http://os-201804081018/blog/wp-login.php')
d.find_element_by_css_selector('#user_login').send_keys('test')
sleep(1)
d.find_element_by_css_selector('#user_pass').send_keys('test123')
sleep(1)
d.find_element_by_css_selector('#wp-submit').click()
sleep(1)
login_msg = d.find_element_by_css_selector('#wp-admin-bar-my-account').text
if 'test' in login_msg:
print('登录成功用例:pass')
else:
print('登录成功用例:fail')
d.close()
d.quit()
# 用户名为空密码正确填写,登录失败
d = webdriver.Chrome()
d.maximize_window()
d.implicitly_wait(10)
d.get('http://os-201804081018/blog/wp-login.php')
d.find_element_by_css_selector('#user_login').send_keys('')
sleep(1)
d.find_element_by_css_selector('#user_pass').send_keys('test123')
sleep(1)
d.find_element_by_css_selector('#wp-submit').click()
sleep(1)
login_msg = d.find_element_by_css_selector('#login_error').text
if '用户名一栏为空' in login_msg:
print('用户名为空密码正确填写,登录失败:pass')
else:
print('用户名为空密码正确填写,登录失败:fail')
d.close()
d.quit()
之前我们所写的是线性代码
#coding=utf-8
# @Author: SamWang
# @Date: 2019-11-15 16:33:56
# @Last Modified time: 2019-11-16 10:42:48
from selenium import webdriver
from time import sleep
# 登录成功
d = webdriver.Chrome()
d.maximize_window()
d.implicitly_wait(10)
d.get('http://os-201804081018/blog/wp-login.php')
d.find_element_by_css_selector('#user_login').send_keys('test')
sleep(1)
d.find_element_by_css_selector('#user_pass').send_keys('test123')
sleep(1)
d.find_element_by_css_selector('#wp-submit').click()
sleep(1)
login_msg = d.find_element_by_css_selector('#wp-admin-bar-my-account').text
if 'test' in login_msg:
print('登录成功用例:pass')
else:
print('登录成功用例:fail')
d.close()
d.quit()
# 用户名为空密码正确填写,登录失败
d = webdriver.Chrome()
d.maximize_window()
d.implicitly_wait(10)
d.get('http://os-201804081018/blog/wp-login.php')
d.find_element_by_css_selector('#user_login').send_keys('')
sleep(1)
d.find_element_by_css_selector('#user_pass').send_keys('test123')
sleep(1)
d.find_element_by_css_selector('#wp-submit').click()
sleep(1)
login_msg = d.find_element_by_css_selector('#login_error').text
if '用户名一栏为空' in login_msg:
print('用户名为空密码正确填写,登录失败:pass')
else:
print('用户名为空密码正确填写,登录失败:fail')
d.close()
d.quit()
# 密码为空用户名正确填写,登录失败
d = webdriver.Chrome()
d.maximize_window()
d.implicitly_wait(10)
d.get('http://os-201804081018/blog/wp-login.php')
d.find_element_by_css_selector('#user_login').send_keys('test')
sleep(1)
d.find_element_by_css_selector('#user_pass').send_keys('')
sleep(1)
d.find_element_by_css_selector('#wp-submit').click()
sleep(1)
login_msg = d.find_element_by_css_selector('#login_error').text
if '密码一栏为空' in login_msg:
print('密码为空用户名正确填写,登录失败:pass')
else:
print('密码为空用户名正确填写,登录失败:fail')
d.close()
d.quit()
# 用户名正确密码错误时,登录失败
d = webdriver.Chrome()
d.maximize_window()
d.implicitly_wait(10)
d.get('http://os-201804081018/blog/wp-login.php')
d.find_element_by_css_selector('#user_login').send_keys('test')
sleep(1)
d.find_element_by_css_selector('#user_pass').send_keys('tes222t123')
sleep(1)
d.find_element_by_css_selector('#wp-submit').click()
sleep(1)
login_msg = d.find_element_by_css_selector('#login_error').text
if '密码不正确' in login_msg:
print('用户名正确密码错误时,登录失败:pass')
else:
print('用户名正确密码错误时,登录失败:fail')
d.close()
d.quit()
引入单元测试框架
#coding=utf-8
# @Author: SamWang
# @Date: 2019-11-15 16:33:56
# @Last Modified time: 2019-11-16 10:45:53
from selenium import webdriver
from time import sleep
import unittest
class mytest(unittest.TestCase):
def setUp(self):
pass
def tearDown(self):
pass
def test_login_success(self):
# 登录成功
d = webdriver.Chrome()
d.maximize_window()
d.implicitly_wait(10)
d.get('http://os-201804081018/blog/wp-login.php')
d.find_element_by_css_selector('#user_login').send_keys('test')
sleep(1)
d.find_element_by_css_selector('#user_pass').send_keys('test123')
sleep(1)
d.find_element_by_css_selector('#wp-submit').click()
sleep(1)
login_msg = d.find_element_by_css_selector('#wp-admin-bar-my-account').text
if 'test' in login_msg:
print('登录成功用例:pass')
else:
print('登录成功用例:fail')
d.close()
d.quit()
def test_login_username_empty(self):
# 用户名为空密码正确填写,登录失败
d = webdriver.Chrome()
d.maximize_window()
d.implicitly_wait(10)
d.get('http://os-201804081018/blog/wp-login.php')
d.find_element_by_css_selector('#user_login').send_keys('')
sleep(1)
d.find_element_by_css_selector('#user_pass').send_keys('test123')
sleep(1)
d.find_element_by_css_selector('#wp-submit').click()
sleep(1)
login_msg = d.find_element_by_css_selector('#login_error').text
if '用户名一栏为空' in login_msg:
print('用户名为空密码正确填写,登录失败:pass')
else:
print('用户名为空密码正确填写,登录失败:fail')
d.close()
d.quit()
def test_login_password_empty(self):
# 密码为空用户名正确填写,登录失败
d = webdriver.Chrome()
d.maximize_window()
d.implicitly_wait(10)
d.get('http://os-201804081018/blog/wp-login.php')
d.find_element_by_css_selector('#user_login').send_keys('test')
sleep(1)
d.find_element_by_css_selector('#user_pass').send_keys('')
sleep(1)
d.find_element_by_css_selector('#wp-submit').click()
sleep(1)
login_msg = d.find_element_by_css_selector('#login_error').text
if '密码一栏为空' in login_msg:
print('密码为空用户名正确填写,登录失败:pass')
else:
print('密码为空用户名正确填写,登录失败:fail')
d.close()
d.quit()
def test_login_password_error(self):
# 用户名正确密码错误时,登录失败
d = webdriver.Chrome()
d.maximize_window()
d.implicitly_wait(10)
d.get('http://os-201804081018/blog/wp-login.php')
d.find_element_by_css_selector('#user_login').send_keys('test')
sleep(1)
d.find_element_by_css_selector('#user_pass').send_keys('tes222t123')
sleep(1)
d.find_element_by_css_selector('#wp-submit').click()
sleep(1)
login_msg = d.find_element_by_css_selector('#login_error').text
if '密码不正确' in login_msg:
print('用户名正确密码错误时,登录失败:pass')
else:
print('用户名正确密码错误时,登录失败:fail')
d.close()
d.quit()
if __name__ == '__main__':
unittest.main()
封装公共部分
from selenium import webdriver
from time import sleep
import unittest
def login_action(d,username,password):
d.get('http://os-201804081018/blog/wp-login.php')
d.find_element_by_css_selector('#user_login').send_keys(username)
sleep(1)
d.find_element_by_css_selector('#user_pass').send_keys(password)
sleep(1)
d.find_element_by_css_selector('#wp-submit').click()
sleep(1)
class mytest(unittest.TestCase):
def setUp(self):
pass
def tearDown(self):
pass
def test_login_success(self):
# 登录成功
d = webdriver.Chrome()
d.maximize_window()
d.implicitly_wait(10)
login_action(d=d,username='test',password='test123')# 调用登录函数
login_msg = d.find_element_by_css_selector('#wp-admin-bar-my-account').text
if 'test' in login_msg:
print('登录成功用例:pass')
else:
print('登录成功用例:fail')
d.close()
d.quit()
使用setUp和tearDown优化
from selenium import webdriver
from time import sleep
import unittest
def login_action(d,username,password):
d.get('http://os-201804081018/blog/wp-login.php')
d.find_element_by_css_selector('#user_login').send_keys(username)
sleep(1)
d.find_element_by_css_selector('#user_pass').send_keys(password)
sleep(1)
d.find_element_by_css_selector('#wp-submit').click()
sleep(1)
#同一个类下,如果该方法的变量想要能够被其他方法所使用,则在定义变量时,加上一个self.
class mytest(unittest.TestCase):
def setUp(self):
self.d = webdriver.Chrome()
self.d.maximize_window()
self.d.implicitly_wait(10)
def tearDown(self):
self.d.close()
self.d.quit()
def test_login_success(self):
# 登录成功
login_action(d=self.d,username='test',password='test123')# 调用登录函数
login_msg = self.d.find_element_by_css_selector('#wp-admin-bar-my-account').text
if 'test' in login_msg:
print('登录成功用例:pass')
else:
print('登录成功用例:fail')
断言
断言 (判断实际结果与预期结果是否相符)
断言方式 | 作用 |
---|---|
self.assertIn(a,b) | 判断 a 是不是 in b |
self.assertNotIn(a,b) | 判断 a 是不是 not in b |
self.assertEqual(a,b) | 判断 a 是不是 等于 b |
self.assertNotEqual(a,b) | 判断 a 是不是 不等于 b |
from selenium import webdriver
from time import sleep
import unittest
def login_action(d,username,password):
d.get('http://os-201804081018/blog/wp-login.php')
d.find_element_by_css_selector('#user_login').send_keys(username)
sleep(1)
d.find_element_by_css_selector('#user_pass').send_keys(password)
sleep(1)
d.find_element_by_css_selector('#wp-submit').click()
sleep(1)
#同一个类下,如果该方法的变量想要能够被其他方法所使用,则在定义变量时,加上一个self.
class mytest(unittest.TestCase):
def setUp(self):
self.d = webdriver.Chrome()
self.d.maximize_window()
self.d.implicitly_wait(10)
def tearDown(self):
self.d.close()
self.d.quit()
def test_login_success(self):
# 登录成功
login_action(d=self.d,username='test',password='test123')# 调用登录函数
login_msg = self.d.find_element_by_css_selector('#wp-admin-bar-my-account').text
self.assertIn('test',login_msg)
def test_login_username_empty(self):
#用户名为空密码正确填写,登录失败
login_action(d=self.d,username='',password='test123')# 调用登录函数
login_msg = self.d.find_element_by_css_selector('#login_error').text
self.assertIn('用户名一栏为空',login_msg)
def test_login_password_empty(self):
# 密码为空
login_action(d=self.d,username='test',password='')# 调用登录函数
login_msg = self.d.find_element_by_css_selector('#login_error').text
self.assertIn('密码一栏为空',login_msg)
def test_login_password_error(self):
# 用户名正确密码错误时,登录失败
login_action(d=self.d,username='test',password='te124st123')# 调用登录函数
login_msg = self.d.find_element_by_css_selector('#login_error').text
self.assertIn('密码不正确',login_msg)
if __name__ == '__main__':
unittest.main()
封装到public中
如果当前脚本的函数,需要被其他脚本所引用,那么我们就需要创建一个public来存放这些共用的函数.模块
比如将登陆的login_action函数封装到public中
1、在testcase文件夹下创建一个public.py
的文件
2、将login_case.py中的登录函数移动到public.py上
修改后的login_case.py
代码如下
from selenium import webdriver
from time import sleep
import unittest
from public import login_action
#同一个类下,如果该方法的变量想要能够被其他方法所使用,则在定义变量时,加上一个self.
class mytest(unittest.TestCase):
def setUp(self):
self.d = webdriver.Chrome()
self.d.maximize_window()
self.d.implicitly_wait(10)
def tearDown(self):
self.d.close()
self.d.quit()
def test_login_success(self):
# 登录成功
login_action(d=self.d,username='test',password='test123')# 调用登录函数
login_msg = self.d.find_element_by_css_selector('#wp-admin-bar-my-account').text
self.assertIn('test',login_msg)
def test_login_username_empty(self):
#用户名为空密码正确填写,登录失败
login_action(d=self.d,username='',password='test123')# 调用登录函数
login_msg = self.d.find_element_by_css_selector('#login_error').text
self.assertIn('用户名一栏为空',login_msg)
def test_login_password_empty(self):
# 密码为空
login_action(d=self.d,username='test',password='')# 调用登录函数
login_msg = self.d.find_element_by_css_selector('#login_error').text
self.assertIn('密码一栏为空',login_msg)
def test_login_password_error(self):
# 用户名正确密码错误时,登录失败
login_action(d=self.d,username='test',password='te124st123')# 调用登录函数
login_msg = self.d.find_element_by_css_selector('#login_error').text
self.assertIn('密码不正确',login_msg)
if __name__ == '__main__':
unittest.main()
修改后的public.py
代码如下
from time import sleep
def login_action(d,username,password):
d.get('http://os-201804081018/blog/wp-login.php')
d.find_element_by_css_selector('#user_login').send_keys(username)
sleep(1)
d.find_element_by_css_selector('#user_pass').send_keys(password)
sleep(1)
d.find_element_by_css_selector('#wp-submit').click()
sleep(1)
# coding:utf-8
import unittest
import os
import HTMLTestRunner
from time import strftime
from HTMLTestRunner import HTMLTestRunner
import time
# python2.7要是报编码问题,就加这三行,python3不用加
#import sys
#reload(sys)
#sys.setdefaultencoding('utf8')
#定义路径及报告
cur_path = os.path.dirname(os.path.realpath(__file__))#获取当前路径
case_path = os.path.join(cur_path, "testcase")# 测试用例的目录名
report_path = os.path.join(cur_path, "report")# 测试报告的目录名
report_name = os.path.sep + strftime('%Y_%m_%d_%H_%M_%S') + '.html'
if __name__ == "__main__":
discover = unittest.defaultTestLoader.discover(case_path,"*case.py")#两个参数(路径,规则)
run = HTMLTestRunner(title="测试报告",
description="测试用例参考",
stream=open(report_path + report_name, "wb"),
)
run.run(discover)
相关下载软件
链接:百度云提取码:3u3l
由于Fiddler需要.net环境所以需要先安装 .net
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VKSBLtrL-1617696547071)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230172054580.png)]
安装.net就比较简单了。傻瓜式安装即可
安装fiddler证书生成器[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-c7QzT11S-1617696547073)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230172133965.png)]
打开Fiddler,点击工具栏中的Tools—>Options–>https设置选项,勾选选择项
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qQWkg26X-1617696547074)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230172304363.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9g6XtCEM-1617696547075)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230172314242.png)]
点击Actions,点击第二项:Export Root Certificate to Desktop,这时候桌面上会出现证书FiddlerRoot.cer文件,点击OK设置成功,关闭fiddler
PC端,在浏览器中导入证书FiddlerRoot.cer,以谷歌浏览器为例说明,在浏览器上输入: chrome://settings/
1、进入设置界面点击最下面的高级然后选择管理证书在受信任的根证书颁发机构,对证书进行导入
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zkXr8hQp-1617696547075)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230172405656.png)]
选择刚刚导入到桌面的证书即可点击下一步然后选择浏览找到刚刚导出的证书然后一路next,直到弹出安全性警告,点击是
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tSXqUpsG-1617696547076)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230172454456.png)]
然后重启fiddler即可
基本介绍
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VVAkNlsd-1617696547077)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230173134465.png)]
查看请求的消耗的时间
选择一个请求,点击statistics
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iSCPXAeX-1617696547078)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230173120321.png)]
清除全部请求
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ssDV9DZx-1617696547078)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230173109022.png)]
查看请求与响应
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4Z2vU7NS-1617696547079)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230173056213.png)]
请求头
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-h6YREw7u-1617696547080)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230173041161.png)]
请求发送的数据
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4YPL0rsO-1617696547080)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230173028364.png)]
响应头
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Q21R3pEA-1617696547081)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230173017590.png)]
响应数据
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7MWTZh2n-1617696547081)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230173003693.png)]
设置fiddler过滤请求
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-F5HTqBt1-1617696547082)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230172950360.png)]
根据内外网切换
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Vz4ZYjqt-1617696547083)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230172937029.png)]
根据输入的域名/IP来过滤
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wmjRzymw-1617696547083)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230172918079.png)]
模拟弱网环境 Ctrl+R
Ctrl+F 搜索 300,修改上传与下载的速度延时
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bTaRG6oA-1617696547084)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230172850444.png)]
修改完成后,ctrl+s
保存即可
点击后才会生效[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tM8oEX9G-1617696547084)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230172834445.png)]
拦截数据,拦截数据又称“打断点”
fiddler抓取HTTPS协
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WAwpIGwV-1617696547085)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230172822601.png)]
然后重启fiddler即可。
fiddler抓取手机的包
ipconfig
)wifi代理设置:
`IOS
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ghqa8C5q-1617696547086)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230172642441.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LbcKGsbJ-1617696547087)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230172651561.png)]
android(一加手机)为例
:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AUeGzudq-1617696547087)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230172545446.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ElZyqdiC-1617696547088)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230172558843.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-A6AvzRIJ-1617696547089)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230172607351.png)]
首先,什么是接口呢?
接口一般来说有两种,一种是程序内部的接口,一种是系统对外的接口。
常见接口:
前端和后端:
在说接口测试之前,我们先来搞清楚这两个概念,前端和后端。
前端是什么呢,对于web端来说,咱们使用的网页,打开的网站,这都是前端,这些都是html、css写的;对于app端来说呢,它就是咱们用的app,android或者object-C(开发ios上的app)开发的,它的作用就是显示页面,让我们看到漂亮的页面,以及做一些简单的校验,比如说非空校验,咱们在页面上操作的时候,这些业务逻辑、功能,比如说你购物,发微博这些功能是由后端来实现的,后端去控制你购物的时候扣你的余额,发微博发到哪个账号下面,那前端和后端是怎么交互的呢,就是通过接口。
前面说的你可能不好理解,你只需记住:前端负责貌美如花,后端负责挣钱养家。
什么是接口测试:
接口测试是测试系统组件间接口的一种测试。接口测试主要用于检测外部系统与系统之间以及内部各个子系统之间的交互点。测试的重点是要检查数据的交换,传递和控制管理过程,以及系统间的相互逻辑依赖关系等。
OK,上面是百度百科上说的,下面才是我说的
其实我觉得接口测试很简单,比一般的功能测试还简单,现在找工作好多公司都要求有接口测试经验
什么是接口测试,本着不懂也要装懂的态度,我会说:所谓接口测试就是通过测试不同情况下的入参与之相应的出参信息来判断接口是否符合或满足相应的功能性、安全性要求。
我为啥说接口测试比功能测试简单呢,因为功能测试是从页面输入值,然后通过点击按钮或链接等传值给后端,而且功能测试还要测UI、前端交互等功能,但接口测试没有页面,它是通过接口规范文档上的调用地址、请求参数,拼接报文,然后发送请求,检查返回结果,所以它只需测入参和出参就行了,相对来说简单了不少。
接口测试的原理
通过测试程序或工具,模拟客户端向服务器发送请求报文,服务器接收请求报文后对相应的报文做出处理,然后再把应答报文发送给客户端,客户端接收应答报文这一个过程。
接口组成
首先,接口文档应该包含以下内容:
1、接口说明
2、调用url
3、请求方法(get\post)
4、请求参数、参数类型、请求参数说明
5、返回参数说明
一个完整的具体的接口测试文档,它告诉接口的地址/或名称,要向接口传入什么参数,每个参数有什么约束条件,成功调用接口时的预期返回结果和调用接口失败时的预期返回结果。
为什么要做接口测试:
大家都知道,接口其实就是前端页面或APP等调用与后端做交互用的,所以好多人都会问,我功能测试都测好了,为什么还要测接口呢?OK,在回答这个问题之前,先举个栗子:
比如测试用户注册功能,规定用户名为6~18个字符,包含字母(区分大小写)、数字、下划线。首先功能测试时肯定会对用户名规则进行测试时,比如输入20个字符、输入特殊字符等,但这些可能只是在前端做了校验,后端可能没做校验,如果有人通过抓包绕过前端校验直接发送到后端怎么办呢?试想一下,如果用户名和密码未在后端做校验,而有人又绕过前端校验的话,那用户名和密码不就可以随便输了吗?如果是登录可能会通过SQL注入等手段来随意登录,甚至可以获取管理员权限,那这样不是很恐怖?
所以,接口测试的必要性就体现出来了:
接口测试要关注什么内容
接口测试怎么测:
所有的软件测试都应追溯到用户需求,接口测试也一样。在接口测试开始前,我们需要得到一份接口测试的需求文档。
产品开发负责人在完成某产品功能的接口文档编写后,在核对无误后下发给对应的接口测试负责人。测试负责人拿到接口文档需要首先做以下两方面的工作。一方面,测试人员要对接口文档中各个接口的功能以及接口中涉及的各个字段的意义和用途进行理解。另一方面,测试人员也应该充分与开发人员交流,理解清楚每个接口用到协议以及各个字段的取值规范和范围。
需求文档有很全面的,也有很简单,如下图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qUinmty2-1617696547089)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230173311510.png)]
不完整的需求
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-o7kHfN64-1617696547090)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230173331296.png)]
接口测试负责人与测试组长或者项目经理沟通测试计划安排。单独一个接口文档涉及的接口过多时,由测试组长按照接口功能的相关性以及复杂性划分接口分发给不同的测试人员进行测试,并制定测试时间以及每日测试工作量。
接口测试用例的编写方式和功能测试类似,针对接口需要输入的参数,设计各种合理和不合理的数据进行测试,然后进行用例的评审。以下面这个需求为例,编写测试用例:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-duFVEeJ4-1617696547090)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230173351875.png)]
测试用例:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WE0q29ms-1617696547091)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230173414648.png)]
接口测试的工具很多,比如 postman、RESTClient、jmeter、loadrunner、SoapUI等,本人首推的测试工具是postman和jmeter
1)、Postman是谷歌的一款接口测试插件,它使用简单,支持用例管理,支持get、post、文件上传、响应验证、变量管理、环境参数管理等功能,可以批量运行,并支持用例导出、导入。
jmeter是一款100%纯Java编写的免费开源的工具,它主要用来做性能测试,相比loadrunner来说,它内存占用小,免费开源,轻巧方便、无需安装,越来越被大众所喜爱。
资源下载百度云,提取码:owi9
先安装JDK
然后等待安装结束即可
变量 | 值 |
---|---|
JAVA_HOME | JDK的安装路径 |
CLASSPATH | .;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar |
PATH | %JAVA_HOME%\bin;%JAVA_HOME%\jre\bin; |
打开环境变量设置界面
win+E
、 系统属性、高级系统设置、环境变量
找到Jmeter压缩包,解压
解压后的直接双击bin目录下的jmeter.bat
文件启动即可
接口演示网站:
https://www.showdoc.cc/372144116738569
unicode编码转中文
http://tool.chinaz.com/tools/unicode.aspx
修改语言
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WkbGexAs-1617696547092)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230173642413.png)]
添加线程组
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hBZIWyfV-1617696547092)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230173702166.png)]
添加http请求
选择线程组,右键添加一个http请求
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jzcUEZFL-1617696547093)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230173713505.png)]
依次填写如下内容
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sx0BaYdb-1617696547094)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230173724338.png)]
添加查看结果树
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CptEaRjk-1617696547095)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230173801199.png)]
修改响应乱码
在Jmeter的bin
目录中有一个jmeter.properties
文件
使用编辑器打开
找到如下这一行
#sampleresult.default.encoding=ISO-8859-1
在这一行下面增加一行
sampleresult.default.encoding=UTF-8
然后保存,重启Jmeter即可
线程组的设置
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YxjhSCmH-1617696547096)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230173818822.png)]
聚合报告(查看汇总结果)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-plgTE2qD-1617696547097)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230173835451.png)]
参数化(CSV数据文件设置)
模拟不同的用户使用不同的数据
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gQbrBaoh-1617696547097)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230173852019.png)]
在Jmeter中使用变量,${变量名}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QXTsQSwn-1617696547098)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230173908817.png)]
信息头管理器
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1Mm9JoKD-1617696547099)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230173921186.png)]
响应断言
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-paQduQqD-1617696547099)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230173933697.png)]
请求默认值
添加请求默认值,如果后续接口没有给该内容传值,则读取默认值
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mLHJhpma-1617696547100)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230173946105.png)]
cookie管理器
添加cookie管理器之后,Jmeter会自动处理所有请求之间的cookie
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0WZpborW-1617696547101)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230173959730.png)]
JSON提取器
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uB3WcQOf-1617696547102)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230174013310.png)]
Json提取器表达式
读取某个key的对应的值
.key的名称
读取列表的内容
[下标]
以Json的方式发送请求参数
Content-Type:application/json
body data
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TYcqkTEl-1617696547102)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230174046273.png)]
\3. 参数以Json形式填写
{"username":"testexam","password":"123123","password_confirmation":"123123"}
集合点
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GgCROwHV-1617696547103)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230174033452.png)]
import os
from time import strftime
#jmeter_bin目录
jmeter_bin = r'D:\apache\apache-jmeter-4.0\bin'
#需要运行的jmeter脚本
jmeter_script = r"D:\api_project\token.jmx"
#测试报告存放路径
result = r'D:\api_project\report'
now = strftime('%Y_%m_%d_%H_%M_%S')
log_path = result + '\\' + now + "\\log"
report_path = result+'\\' + now + "\\report"
os.system("mkdir " +log_path)
os.system("mkdir " +report_path)
command = "jmeter -n -t %s -l %s\\jmeter.log -e -o %s"%(jmeter_script,log_path,report_path)
os.chdir(jmeter_bin)
os.system(command)
jenkins
安装文件进行安装点击next
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dFjQjhrF-1617696547103)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230174245678.png)]
选择安装路径安装,点击next
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gKNs46Eo-1617696547104)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230174256172.png)]
点击install
安装
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-s4XECtMS-1617696547105)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230174310847.png)]
点击finish
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DqWEv9FV-1617696547105)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230174322173.png)]
安装之后默认会打开jenkins网址
http://localhost:8080
默认密码位置
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JIPRt9ou-1617696547106)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230174333499.png)]
插件安装界面
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3L0leKDT-1617696547107)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230174346287.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UEQRg8Fx-1617696547107)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230174403252.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WophY49a-1617696547108)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230174415787.png)]
至此安装结束
新建任务
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PzAvhKOq-1617696547108)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230174501811.png)]
输入任务名称等
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UfNVYCOa-1617696547109)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230174517793.png)]
描述信息
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-31J7sA7i-1617696547110)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230174530109.png)]
构建触发器[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-G9WuWl68-1617696547110)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230174543644.png)]
日程表语法
语法:分钟 小时 天 月 周
总共五个字段,每个字段用空格或者tab键隔开
例子:
20 12 1-25 * *
表示每周每月的1-25号的每天12点20开始执行
25 23 * * *
表示每天的23:25份执行
10 15 * * 1-5
表示周一到周五的每天15:10分执行
增加构建步骤
填写命令
为了防止Jenkins出错,最好是指定Python的目录
语法:
python的安装路径\python 要执行的py文件路径
那么我的命令为:
C:\Python\python G:\api_project\run_jmeter.py
然后保存即可
什么是系统的性能
一个系统做出来了,客户需求说明书上的功能都已经完全且准确无误地实现了,这只表明系统能做事了,但是做得怎么样还有待验证,这里所说的,“做得怎么样”,就可以简单地理解为系统的性能。
什么是系统的性能测试?
性能测试,是指在一定的软件、硬件及网络条件下,通过自动化的测试工具模拟多种正常、峰值以及异常负载条件来对系统的各项性能指标进行测试,从而发现系统的性能瓶颈。
也就是说,通过各种测试策略,模拟真实的用户使用场景,验证系统能“做得怎么样”。
性能测试的常用术语
并发用户,一般分为2种情况。
一种是绝对并发,即所有的用户在同一时刻做同一件事情或者操作,这种操作一般指做同一类型的业务。
一种是相对并发。多个用户对系统发出了请求或者进行了操作,但是这些请求或者操作可以是相同的,也可以是不同的。对整个系统而言,仍然是有很多用户同时对系统进行操作,因此也属于并发的范畴。
并发用户数的误解:关于用户并发的数量,有2种常见的错误观点。 一种错误观点是把并发用户数量理解为使用系统的全部用户的数量或者是系统的注册用户,理由是这些用户可能同时使用系统;还有一种比较接近正确的观点是把在线用户数量理解为并发用户数量。实际上在线用户也不一定会和其他用户发生并发,例如正在浏览网页的用户,对服务器没有任何影响。
单位时间用户向WEB服务器提交的HTTP请求数。点击率和TPS就是一个概念。需要注意的是,这里的点击并非指鼠标的一次单击操作,因为在一次单击操作中,客户端可能向服务器发出多个HTTP请求。
事务响应时间指的是从客户端发起请求开始,到客户端接收到从服务器端返回的响应结束
标准可参考业界的3/5/10原则:
90%的响应时间,是指在一次完整的测试过程中,所有事务的请求时间,按从小到大顺序排序,90%的事物所消耗的时间范围。
吞吐量是我们常见的一个软件性能指标,对于软件系统来说,就是指软件系统在每单位时间内能处理多少个事务/请求等。
用来实现绝对并发
资源利用率指的是对不同系统资源的使用程度,例如服务器的CPU(s),内存,网络带宽等。资源利用率通常以占用最大值的百分比n%来衡量。
性能测试策略
在一定的软件、硬件及网络条件下,通过运行一种或多种业务在不同虚拟用户数量情况下,测试系统的性能指标是否在用户的要求范围内,用于确定系统所能承受的最大有效用户数以及不同用户数下的系统响应时间及服务器的资源利用率。
负载测试强调的是在一定的环境下系统能够达到的峰值指标,大多数的性能测试都是负载测试。这种方法的目的是找到系统处理能力的极限,通过模拟不同数量级的用户,找到如“响应时间不超过10秒”,“服务器平均CPU利用率低于65%”时的用户数。
负载测试场景:
50个用户同时下单请求 响应时间 消耗资源
100个用户同时下单请求 响应时间 消耗资源
150个用户同时下单请求 响应时间 消耗资源
200个用户同时下单请求 响应时间 消耗资源
在一定的软件、硬件及网络条件下,通过模拟大量的虚拟用户向服务器产生负载,使服务器的资源处于极限状态下并长时间连续运行,以测试服务器在高负载情况下是否能够稳定工作。
通过模拟多个用户并发访问一个应用或一个应用的某个功能,同一个存储过程,或接口以及其他并发操作,测试程序是否支持多用户访问,是否存在死锁,线程同步的问题。
疲劳测试,有些公司也叫可靠性测试,是软件系统长时间(8小时,7*24小时)运行系统,检查系统是否能稳定运行,有没有内存泄漏等。
内存溢出–需要占用的内存超过系统的可用内存 (OOM:OutOfMemory)
内存泄漏–内存被长期占用,无法被回收。
程序没有做多线程处理:程序在单用户场景下运行成功,多用户运行则失败,提示连不上服务器。
线程同步的问题:程序实现的功能是,随机给用户分配不同的任务,单用户运行时,能成功分配;多用户并发申请任务时,所有用户得到的任务都是一样的。
性能测试指标
一般来说,性能测试关注的指标有这些:
1、事务成功率
2、事务平均响应时间和90%的事务响应时间
3、吞吐量(TPS)
4、CPU,内存,IO使用率
性能测试流程
Jmeter简介
Jmeter是一种预测系统行为和性能的负载测试工具。它通过模拟实际用户的操作行为和实行实时性能监测,来帮助测试人员更快的查找和发现问题。
Jmeter工作原理图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iIev2zEa-1617696547111)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230174708375.png)]
Jmeter环境的搭建:
因为JMeter是JAVA程序开发的,所以要先安装JDK;
配置JAVA环境变量,包括:JAVA_HOME,PATH,CLASSPATH;
双击jmeter的bin目录里面的jmeter.bat文件,就可以启动Jmeter。
安装
首先现在根目录创建一个文件夹mkdir /nmon
然后再 /nmon下创建一个log文件夹
先cd /nmon
然后 mkdir ./log
给予执行权限
chmod -R a+x ./nmon_x86_rhel5
使用Nmon监控
为了配合性能测试,我们往往需要将一个时间段内系统资源消耗情况记录下来,这时可以使用命令在远程窗口执行命令
cd /nmon
./nmon_x86_rhel5 -f -N -t -m 监控数据存放路径 -s 间隔时间 -c 监控次数
-m 数据存放的路径
-s 间隔时长(秒)
-c 监控次数
比如我将日志的存放路径放在/nmon/log
,总共监控80次,每次间隔5秒
./nmon_x86_rhel5 -f -N -t -m /nmon/log -s 5 -c 80
监控完成后,进入到/nmon/log
目录中,可以看到产生的日志文件,将其导出到本地
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HzPDLYEb-1617696547113)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230175316641.png)]
安全警告,选项,启用此内容
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-arNzNhIR-1617696547113)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230175337923.png)]
点击分析nmon数据,选择刚刚导出的nmon文件
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cbKNtPVm-1617696547114)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230175409150.png)]
他会转换成excel表格的形式
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0ZIFrIbv-1617696547115)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230175419678.png)]
查看CPU
CPU主要在CPU_ALL
这一个表中
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XBHsg5nO-1617696547115)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230175430296.png)]
其中CPU%就是CPU的使用率
首先先截取出自己在执行性能测试这段时间的资源的使用情况
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nWkf5gQG-1617696547116)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230175443426.png)]
再生成折线图
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ubVYR6Nq-1617696547116)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230175523242.png)]
查看内存
内存的使用情况主要在MEM
这一个表中
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mZxqFgHx-1617696547117)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230175550631.png)]
内存占用率 = (总内存-可用内存)/总内存
可用内存 = 空闲内存 + 缓存 + 缓冲区
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ejb3kGIl-1617696547118)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230175623659.png)]
删除多余表格
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4ecyBJyq-1617696547118)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230175644067.png)]
使用 公式生成,设置以百分比展示
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-i6HCB3y8-1617696547119)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230175704806.png)]
修改配置文件
- 允许分布式压力
先将jmeter的bin目录中的jmeter.properties
文件
找到这一行#server.rmi.ssl.disable=false
在这一行下面添加一行server.rmi.ssl.disable=true
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ROqvjWK7-1617696547119)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230175744814.png)]
- 大脑还需要查找如下内容,来添加自己预计需要控制的压力机
remote_hosts
找到如下内容
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-M4dDXFAk-1617696547120)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230175805447.png)]
在remote_hosts=IP地址1,IP地址2
- 查看返回内容
查找关键字#mode=Standard
,把前面的#
号去掉,保存退出,重启jmeter,就可以
- 确保压力机与大脑(主机)的参数化文件路径一致
比如脚本中参数化文件的路径是D:\ecshop_pf\username.txt
那么就必须确保所有的主机与压力机都拥有此文件D:\ecshop_pf\username.txt
其次,所有的压力机需要平分所有的数据,比如,原本参数化文件有120条数据,
我使用了3台压力机,那么所有压力机就一台40条数据
- 最后压力机需要开启被控制的模式
在Jmeter的bin 目录中,双击jmeter-server.bat
文件,运行后,可被远程 控制
- 大脑控制其余压力机运行
打开jmeter.bat文件
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-myVYAANJ-1617696547121)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230175820308.png)]
若没有返回数据
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6uccVlD9-1617696547121)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230175835689.png)]
如果开启不了Jmeter-server.bat
关闭oracle服务
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LOmlaAts-1617696547122)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230175846958.png)]
找到这两个
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BegoOpIz-1617696547123)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230175856201.png)]
安装
下载百度云地址
提取码:46a0
下载后解压到当前文件夹
会得到一个adt文件夹
将adt中的sdk\platform-tools
目录加入到环境变量
然后在dos界面就可以使用adb命令
比如adb version
使用
ADB命令使用详解
ADB是一个 客户端-服务器端 程序, 其中客户端是你用来操作的电脑, 服务器端是android设备.我们后期将会使用adb+monkey对app进行性能测试。
安卓设备以夜神模拟器为例子,夜神模拟器默认IP: 127.0.0.1:62001
常见adb命令
adb connect 设备ip地址
adb devices
adb install 需要安装的apk路径
比如我要安装的apk:D:\apk\dr.fone3.2.0.apk
那么我的命令是:adb install D:\apk\dr.fone3.2.0.apk
adb logcat 查看手机日志
adb logcat -v time 查看手机日志(带上时间)
adb logcat -c
包名,在手机中表示app的标识。
adb logcat -c
START
关键字的日志adb logcat -v time | findstr START
ctrl+c
终止日志的获取包名
/[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NiuabGak-1617696547123)(https://www.kancloud.cn/samwang/daily/images/screenshot_1574662679605.png)]
adb uninstall 包名
adb push 本地路径 android路径
adb pull android路径 本地路径
比如将D:\a.txt 文件上传到 安卓/data目录下
adb push D:\a.txt /data
比如将 安卓/data目录下a.txt文件 下载到D:\test中
adb pull /data/a.txt D:\test
adb shell monkey -p 包名 -v 事件数/次数
monkey命令后面可以带很多参数,常见的除了-v、-p还有-s,-s 后面加上monkey上一次运行时候的产生seed值,就可以让monkey重复上一次运行时的操作路径,从而实现回归测试。
adb shell monkey -p 包名 -s seed值 -v 次数
adb shell monkey -p 包名 -v 事件数/次数 > D:\monkey.log
adb logcat -v time > E:\share\logcat.log
把logcat日志导入到E盘的share目录下。
使用monkey进行性能测试
步骤如下
adb logcat -c
adb logcat -v time > D:\logcat.txt
adb shell monkey -p 包名 -v 次数 > D:\monkey.txt
adb 连接真机
数据线连接上手机与电脑,安装好驱动即可
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BZseFApk-1617696547124)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230180217584.png)]
数据线连接上手机与电脑,安装好驱动
输入命令`adb tcpip 5555
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8ki0bjTm-1617696547125)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230180201308.png)]
手机与电脑处于同一网络之下,并且查询到手机的wifi的ip地址
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sMbAdcKF-1617696547126)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230180151317.png)]
输入命令`adb connect 手机IP地址
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QEyr72UF-1617696547127)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230180104153.png)]
手机与电脑处于同一网络下
安装adbwireless
应用即可
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Bg0r6RGf-1617696547127)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230180052290.png)]
下载百度云
提取码`:`sfu6
前提条件:1.安装selenium,2.安装JDK
下载并安装nodejs官网根据你电脑的位数来下载
下载好后,傻瓜式默认安装。
安装完后输入:npm -v
,出现以下信息,表示安装成功。
通过官网下载,下载后双击安装
Android SDK 可以看做用于开发和运行Android 应用的一个软件
官方下载地址
国内镜像地址
官网最底部下载对应的SDK 工具包就可以了
环境变量配置
变量名:ANDROID_HOME
变量值:SDK的路径
变量名:PATH
变量值:;%ANDROID_HOME%\platform-tools;%ANDROID_HOME%\tools;
在dos界面输入命令 python -m pip install Appium-Python-Client
至此安装结束
夜神模拟器win7系统下的连接方法: adb connect 127.0.0.1:62001
夜神模拟器win10系统下的连接方法: adb connect 127.0.0.1:62025
查看当前运行的APP的包名和打开的Activity
adb shell "dumpsys window | grep mCurrentFocus"
配置Python连接手机app
desired = {
"platformName": "Android",
"platformVersion": "设备版本",
"deviceName": "设备名称",
"appPackage": "包名",
"appActivity": "activity名称",
"unicodeKeyboard": "True",
"restKeyboard": "True"
}
首先需要现在appium中开启服务
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eIICMKuY-1617696547128)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230180350898.png)]
点击后如下
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xywl2pa4-1617696547129)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230180400183.png)]
在appium中配置json文件
{
"platformName": "Android",
"platformVersion": "设备版本",
"deviceName": "设备名称",
"appPackage": "包名",
"appActivity": "activity名称",
"unicodeKeyboard": "True",
"restKeyboard": "True"
}
然后点击
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AqChDFXe-1617696547130)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230180430762.png)]
填写json内容
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rOn5fg3L-1617696547130)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230180457706.png)]
填写完成后,点击保存
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bs0O3yW3-1617696547131)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230180523021.png)]
当然你也可以保存该配置至电脑中
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3DDYvfSK-1617696547131)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230180535278.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mHAa6e1c-1617696547132)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230180544582.png)]
定位元素
start_session
就可以开始定位元素了
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EBLZLcVo-1617696547132)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230180600883.png)]
基本使用[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kXu9jhJw-1617696547133)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230180620074.png)]
判断属性是否唯一[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-irzm8mnD-1617696547133)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230180634553.png)]
基本定位
from appium import webdriver
from time import sleep
# 配置需要操作的手机以及app
desired = {
"platformName": "Android",
"platformVersion": "5.1.1",
"deviceName": "127.0.0.1:62001",
"appPackage": "com.mymoney",
"appActivity": "com.mymoney.biz.splash.newguide.NewGuideActivity",
"unicodeKeyboard": "True",
"restKeyboard": "True"
}
# 连接appium,打开app
d = webdriver.Remote('http://127.0.0.1:4723/wd/hub',desired)
sleep(5)
# 点击下一步,使用id定位
d.find_element_by_id('com.mymoney:id/next_btn').click()
sleep(3)
# 再次点击下一步,使用class定位
d.find_element_by_class_name('android.widget.Button').click()
sleep(3)
# 点击开始随手记
d.find_element_by_xpath('/hierarchy/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout/android.widget.FrameLayout/android.widget.FrameLayout/android.widget.LinearLayout/android.support.v4.view.ViewPager/android.widget.LinearLayout[2]/android.widget.LinearLayout[2]/android.widget.Button[1]').click()
sleep(10)
# 关闭app
d.close_app()
UIAutomator定位
使用方法 find_element_by_android_uiautomator() 可以运用UiAutomator元素定位。
UiAutomator提供一下三种方式来定位:
•id定位d.find_element_by_android_uiautomator('new UiSelector().resourceId("id的值")')
•text定位d.find_element_by_android_uiautomator('new UiSelector().text("text的内容")')
•class name定位d.find_element_by_android_uiautomator('new UiSelector().className("className的值")')
定位一组元素
Swipe 两点之间的滑动操作
我们在使用App的过程中,经常会在屏幕上进行滑动的操作,如,刷新新闻,刷朋友圈等,会做上下滑动的动作;如果是看图片,就会左右移动。在Appium里面,我们是用swipe()这个方法来实现这个操作。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SO4stZmo-1617696547134)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201230180652163.png)]
语法:
swipe(起始横坐标,起始纵坐标,目标横坐标,目标纵坐标)
获取屏幕尺寸d.get_window_size()
获取屏幕大小,以词典的方式返回
想右滑动,y轴不变,x轴由小到大即可
# 获取屏幕大小,以词典的方式返回
size = d.get_window_size()
width = size['width']
height = size['height']
x1 = 0.2 * width
x2 = 0.9 * width
y = 0.5*height
d.swipe(x1,y,x2,y)
连续滑动
swipe滑动操作,一般是两点之间的滑动,而实际使用过程中用户可能要进行一些多点连续滑动操作。如手势密码操作,切西瓜等场景。那么在Appium中该如何模拟这类操作呢?
TouchAction
TouchAction包含一些列操作,比如按压、长按、点击、移动、暂停。由这些不同操作可以组成一套动作。使用TochAction需要先导入对应的模块:
from appium.webdriver.common.touch_action import TouchAction
连续滑动需要导入from appium.webdriver.common.touch_action import TouchAction
方法:press() 按压一个元素或坐标点(x,y)。
press(element)
press(x,y)
方法:相比press()方法,long_press()多了一个入参,就是长按的时间。duration以毫秒为单位。1000表示按一秒钟。其用法与press()方法相同。
long_press(element,duration=1000)
long_press(x,y,duration=1000)
方法:tap() 对一个元素或控件执行点击操作。用法参考press()。
tap(element)
tap(x,y)
方法:move_to() 将指针从上一个点移动到指定的元素或点。
move_to(element)
move_to(x,y)
方法:wait()暂停脚本的执行,单位为毫秒。
wait(ms)
方法release() ,我们滑动总要停止吧?怎么停止?就是用这个方法停止。
release()
方法:perform() 把要执行的操作发送到Appium服务器,即让要执行的操作生效。
perform()
示例代码
from appium import webdriver
from time import sleep
from appium.webdriver.common.touch_action import TouchAction
# 配置需要操作的手机以及app
desired = {
"platformName": "Android",
"platformVersion": "5.1.1",
"deviceName": "127.0.0.1:62001",
"appPackage": "com.mymoney",
"appActivity": "com.mymoney.biz.splash.newguide.NewGuideActivity",
"unicodeKeyboard": True,
"restKeyboard": True
}
# 连接appium,打开app
d = webdriver.Remote('http://127.0.0.1:4723/wd/hub',desired)
sleep(5)
# UIAutomator定位之id定位
d.find_element_by_android_uiautomator('new UiSelector().resourceId("com.mymoney:id/next_btn")').click()
sleep(2)
# 再次点击下一步,使用class定位
d.find_element_by_android_uiautomator('new UiSelector().className("android.widget.Button")').click()
sleep(2)
# 通过text定位,进入首页
d.find_element_by_android_uiautomator('new UiSelector().text("开始随手记")').click()
sleep(10)
# 点击更多
d.find_element_by_id('com.mymoney:id/nav_setting_btn').click()
sleep(2)
# 往上滑动
# # 获取屏幕大小,以词典的方式返回
size = d.get_window_size()
width = size['width']
height = size['height']
x = 0.5 * width
y1 = 0.2 * height
y2 = 0.9 * height
d.swipe(x,y2,x,y1)
sleep(2)
# 点击高级
d.find_element_by_android_uiautomator('new UiSelector().text("高级")').click()
sleep(2)
d.find_element_by_android_uiautomator('new UiSelector().text("密码与手势密码")').click()
sleep(2)
d.find_element_by_android_uiautomator('new UiSelector().text("手势密码保护")').click()
sleep(2)
print('连续滑动')
TouchAction(d).press(x=169,y=190).wait(1000).move_to(x=274,y=190).move_to(x=270,y=293).move_to(x=170,y=382).release().perform()
sleep(3)
d.close_app()
H5元素的定位
在混合开发的App中,经常会有内嵌的H5页面。针对这种场景直接使用前面所讲的方法来进行定位是行不通的,因为前面的都是基于Andriod原生控件进行元素定位,而Web网页是单独的B/S架构,两者的运行环境不同因此需要进行上下文(context)切换,然后对H5页面元素进行定位操作。
什么是context呢?在程序中context我们可以理解为当前对象在程序中所处的一个环境。 比如前面提到的App一个界面是属于Activity类型,也就是Android界面环境,但是当访问内嵌的网页是属于另外一个环境(网页环境),两者处于不同的一个环境。
contexts
,以列表的形式返回all_context = d.contexts
print(all_context)
switch_to.context()
all_context = d.contexts
d.switch_to.context(all_context[1])
chrome://inspect/#devices
,进入调试模式chrome://inspect/#devices
地址中,检查是否显示对应的webview,如没有,则当前未开启调试模式。上图App已经开启了开启调试模式。
比如我的版本是74.0.3729.136
,我就需要下载相对应版本的谷歌浏览器驱动
下载下来之后创建一个文件夹存放该驱动,并且解压
比如,我在D盘创建了一个app_chromederiver
目录,将驱动移动进去并解压
另外在脚本中的desired
中增加一项chromedriverExecutable
指定驱动位置即可
比如我的:
# 配置需要操作的手机以及app
desired = {
"platformName": "Android",
"platformVersion": "5.1.1",
"deviceName": "127.0.0.1:62001",
"appPackage": "com.wondershare.drfone",
"appActivity": "com.wondershare.drfone.ui.activity.Main2Activity",
"unicodeKeyboard": True,
"restKeyboard": True
}
# 由于appium自带了一个chromedriver,所以我们需要指定appium使用我们下载下来的对应版本的驱动
# 在desired中,增加一个key>>> chromedriverExecutable,它的值就是指定的驱动位置
desired['chromedriverExecutable'] = R"D:\app_chromederiver\chromedriver.exe"
完整H5页面代码演示
from appium import webdriver
from base import desired
from time import sleep
desired['appPackage'] = 'com.wondershare.drfone'
desired['appActivity'] = 'com.wondershare.drfone.ui.activity.WebViewActivity'
# 指定appium使用chromedriver.exe
desired['chromedriverExecutable'] = R'D:\chromedriver.exe'
d = webdriver.Remote('http://127.0.0.1:4723/wd/hub',desired)
print('开始等待20s')
sleep(20)
# contexts 获取所有的上下文
all_contexts = d.contexts
print(all_contexts)
sleep(1)
# 切换上下文
d.switch_to.context(all_contexts[1])
print('切换上下文')
sleep(2)
d.find_element_by_id('email').send_keys('[email protected]')
sleep(2)
d.find_element_by_class_name('btn_send').click()
sleep(2)