一、大纲
1. 核心重点(第二章)
2. 提高代码质量,自动化水平(第三、四、五、六章)
3. 项目实战(第七章)
4. 理论及环境与定位(第一章)
二、自动化相关理论知识
2.1 自动化
说明:让机器设备代替人为完成指定目标的而过程
优点:
1. 减少劳动力
2. 提高效率(批量生产)
3. 提高产品质量
4. 规格统一标准
2.2 自动化测试
说明:让程序或工具代替人为对程序功能验证的过程
解决:
1. 回归测试[重点]
2. 压力测试
3. 兼容性(1. 浏览器、2. 分辨率 3. 操作系统)
4. 提高测试效率
优点:
1. 在最短时间内运行最多的bug
2. 脚本重复运行
3. 减少人为错误
4. 克服手工测试局限性(图片大小)
误区:
1. 自动化测试比手工厉害
2. 自动化测试比手工发现更多bug
3. 自动化测试可以完全替代手工测试
4. 软件所有功能都适合自动化测试。
2.3 自动化测试分类
1. Web自动化测试【本阶段学习】
2. 移动自动化测试(app自动化)
3. 接口自动化(工具、代码)
4. 单元测试
2.4 web自动化测试
概念:让程序代替人为对web项目进功能验证过程
什么web项目适合自动化?
1. 需求变动不频繁
2. 需要回归测试项目
3. 项目周期长
web自动化开始进行阶段?
手工测试之后(1. 时间问题 2. 功能不完善)
web自动化所属分类
1. 黑盒测试
2. 灰盒测试
3. 白盒测试
提示:
1. 以上分类为站在代码可见度上划分
2. web自动化测试属于黑盒测试
二、自动化工具
2.1 主流自动化工具
1. QTP: 收费 支持(支持web、桌面软件自动化)
2. selenium: 免费 开源 只支持web项目 【本阶段学习】
3. Robot framework: 基于python扩展关键字驱动自动化工具。2014年停止更新
2.2 什么是selenium?
一个web自动化测试工具, 中文的意思:硒
2.3 特点:
1. 开源、免费
2. 跨平台(Linux windows mac)
3. 支持多浏览器:谷歌 火狐 IE
4. 支持多语言:python、java...等等
5. 成熟稳定:已经被 谷歌、百度大型公司广泛使用
6. 功能强大:支持商业化大部分功能,并且由于开源,可以定制化需求功能。
2.4 slenium家族介绍
版本:
selenium1.0
1. selenium IDE (录制自动化代码工具)
2. selenium Grid (分布式工具:同时启动多个浏览器)
3. selenium RC(通过JS模拟浏览器,实现自动化方式)
selenium2.0(稳定推荐版)
selenium2.0 = selenium1.0+webdriver
selenium3.0
2.0升级版,支持JAVA8、woindows10 Edge浏览器、safa浏览器
提示:无论是通过2.0还是3.0编写的自动化脚本,API方法是不变的,唯一不同就是环境不同。
三、selenium
3.1 安装:
1). 通过pip包管理工具去安装
安装:
pip install selenium
查看:
pip show selenium
卸载:
pip uninstall selenium
扩展:
1. 安装指定版本 pip install selenium==版本号 如:pip install selenium==2.48.0
2. 如何查看可安装按本? 指定版本号为错误版本号
3. pip是python中包管理工具(可以安装,卸载、查看python工具)
4. pip list:查看通过pip包管理工具安装的插件或工具
提示:
1. 使用pip必须联网
2. 默认安装python3.5版本以上工具,自带pip包管理工具,默认会自动安装并且添加path环境变量
2). 通过pycharm去安装【推荐】
推荐原因:安装到当前工程环境内。
操作:
File(文件菜单)-->setting-->Project: 当前工程名称-->Project Interpreter--点击+号安装相应包和版本
提示:如果使用pip install 插件名 安装过后,打开pycharm,导包操作时,提示找不到此包,那就说明使用pip install 默认安装的路径和当前工程所有的环境路径不是同一个环境,进行以上处理可以解决问题。
3.2 浏览器及驱动安装
浏览器
火狐:可以官网或百度获取浏览器版本。
谷歌:通过百度。
驱动:
1. 火狐:https://github.com/mozilla/geckodriver/releases/
2. 谷歌:http://chromedriver.storage.googleapis.com/index.html
应用:
1. 将浏览器驱动放到指定文件夹
2. 将浏览器驱动所在目录添加到系统path环境变量中
(选中我的电脑/此电脑-右键-->属性-->高级系统设置-->高级(环境变量)-->path(如果是wind7路径与路径之间需要添加分号))
注意:
1. 浏览器驱动必须和浏览器版本对应(查看下载驱动时,有告知响应的浏览器版本)
2. 获取浏览器48版本以下,内置驱动。
3.3 科普path
说明:指定系统搜索的目录
dos命令默认搜索顺序:
1. 检测是否为内部命令
2. 检测是否为当前目录下可执行文件
3. 检测path环境变量指定的目录
提示:
1. 如果以上搜索目录都检测不到输入的命令或可执行文件,系统会抛出不是内部或外部命令...
2. 在web环境中,如果不将浏览器驱动添加到path中,selenium在运行的时候会提示浏览器驱动有误。
3.4 第一个案例
# 导包
from selenium import webdriver
from time import sleep
# 获取浏览器驱动
driver = webdriver.Chrome()
# 打开url
driver.get("http://www.baidu.com")
# 暂停3秒
sleep(3)
# 关闭浏览器驱动
driver.quit()
四、元素定位
4.1 为什么要使用元素定位?
要使用web自动化操作元素,必须首先找到此元素。
4.2 定位工具
火狐:Firebug (F12获取直接点击 Friebug图标)
谷歌:F12键(开发者工具)
4.3 定位元素时依赖于什么?
1. 标签名
2. 属性
3. 层级
4. 路径
4.4 定位方式
1. id
2. name
3. class_name(使用元素的class属性定位)
4. teg_name(标签名称 <标签名 .../>)
5. link_text(定位超连接 a标签)
6. partial_link_text(定位超链接 a标签 模糊)
7. xpath(基于元素路径)
8. css(元素选择器)
汇总:
1. 基于元素属性特有定位方式(id\name\class_name)
2. 基于元素标签名称定位:tag_name
3. 定位超链接文本(link_text、partial_link_text)
4. 基于元素路径定位(xpath)
5. 基于选择器(css)
id 定位:
说明:
1. 通过元素的id属性定位,id一般情况下在当前页面中是唯一。
方法:
driver.find_element_by_id(id)
提示:
元素必须要有id属性。
案例:
# 导包
# 获取浏览器驱动对象
# 打开url
# 查找用户名文本框
# 查找密码框文本框
# 输入用户名
# 输入密码
# 暂停3秒
# 关闭驱动
提示:
1. 输入方法:send_keys("输入内容");
2. 退出浏览器驱动:driver.quit();
3. 打开url: driver.get(url)
4. 导包:from selenium import webdriver
5. 获取火狐浏览器驱动对象 driver = webdriver.Firefox()
name 定位:
说明:
1. 通过元素的name属性来定位, name一般名称为重复。
方法:
drivr.find_element_by_name(name)
提示:
元素必须要有name属性
class_name定位:
说明:
1. 通过元素的class属性来定位,class属性一般为多个值。
方法:
driver.find_element_by_class_name()
提示:
元素必须要有class属性
提示:
id: 一般为唯一标识符。
name:可以重名
class:多个命名。
tag_name
link_text
partial_link_text
xpath
css
一、元素定位方法
1.1 tag_name (了解)
说明:是通过元素的标签名称来定位,标签名(查看元素时尖括号(<)紧挨着的单词或字母就是标签名)
(标签名也就是元素名)
方法:driver.find_element_by_tag_name(“标签名”)
注意:
1. 如果页面中存在多个相同标签,默认返回第一个标签元素。
1.2 link_text
说明:定位超链接标签
方法:driver.find_element_by_link_text()
注意:
1. link_text:只能使用精准匹配(a标签的全部文本内容)
1.3 partial_link_text【推荐】
说明:定位超链接标签
方法:driver.find_element_by_partial_link_text()
注意:
1. 可以使用精准或模糊匹配,如果使用模糊匹配最好使用能代表唯一的关键词
2. 如果有多个值,默认返回第一个值
二、Xpath 和 Css 定位
2.1 为什么使用Xpath和css定位?
1. id,name,class:依赖于元素这三个对应的属性,如果元素没有以上三个属性,定位方法不能使用。
2. link_text,partial_link_text:只适合超链接
3. tag_name:只能找页面唯一元素,或者 页面中多个相同元素中的第一个元素
2.2 什么是Xpath定位?
说明:基于元素的路径
2.3 xpath介绍
1. xpath是XML Path简称;
(xml是一种标记语言,焦点:数据存储于传递(配置文件) 后缀.XML)
2.4 Xpath常用的定位策略:
1. 路径
1). 绝对路径:
语法:以单斜杠开头逐级开始编写,不能跳级。如:/html/body/div/p[1]/input
2). 相对路径
语法:以双斜杠开头,双斜杠后边跟元素名称,不知元素名称可以使用*代替。
如: //input
//*
2. 路径结合属性
语法:在Xpath中,所有的属性必须使用@符号修饰 如://*[@id='id值']
3. 路径结合逻辑(多个属性)
语法://*[@id="id值" and @属性='属性值']
4. 路径结合层级
语法://*[@id='父级id属性值']/input
提示:
1. 一般见识使用指定标签名称,不使用*代替,效率比较慢。
2. 无论是绝对路径和相对路径,/后面必须为元素的名称或者*
3. 扩展:在工作中,如果能使用相对路径绝对不使用绝对路径。
2.5 Xpath扩展
1. //*[text()='XXX'] # 定位文本值等于XXX的元素
提示:一般适合 p标签,a标签
2. //*[contains(@属性,'xxx')] # 定位属性包含xxx的元素 【重点】
提示:contains为关键字,不可更改。
3. //*[starts-with(@属性,'xxx')] # 定位属性以xxx开头的元素
提示:starts-with为关键字不可更改
三、CSS定位
说明:
1. CSS一种标记语言,焦点:数据的样式。控制元素的显示样式,就必须先找到元素,在css标记语言中找元素使用css选择器;
2. css定位就是通过css选择器工具进行定位。
3. 极力推荐使用,查找元素的效率比xpath高,语法比xpath更简单。
方法:
driver.find_element_by_css_selector()
常用测试略:
1. id 选择器
前提:元素是必须有id属性
语法:#id 如:#passwordA
2. class 选择器
前提:元素是必须有class属性
语法:.class 如:.telA
3. 元素选择器
语法:element 如:input
4. 属性选择器
语法:[属性名=属性值]
5. 层级选择器
语法:
1. p>input
2. p input
提示:>与空格的区别,大于号必须为子元素,空格则不用。
扩展:
1. [属性^='开头的字母'] # 获取指定属性以指定字母开头的元素
2. [属性$='结束的字母'] # 获取指定属性以指定字母结束的元素
3. [属性*='包含的字母'] # 获取指定属性包含指定字母的元素
复制xpath:/html/body/form/div/fieldset/p[1]/input
复制最简://*[@id="userA"]
复制CSS路径:html body form div#zc fieldset p#p1 input#userA
提示:
1. 虽然借助工具可以快速生成xpath路径和css语法,但是前期不建议使用。
2. 工具在智能,没有人智能。
五、定位一组元素
方法:driver.find_elements_by_xxx()
返回结果:类型为列表,要对列表进行访问和操作必须指定下标或进行遍历,[下标从0开始]
六、扩展8种元素定位的底层实现
方式:driver.find_element(By.xxx, ‘value’)
参数说明:
By.xxx :为By类的类型 如:By.ID
value: 元素的定位值 如: “userA”
By类:需要导包 位置: from selenium.webdriver.common.by import By
1. 元素操作
2. 浏览器常用操作API
3. 元素操作其他常用操作API
4. 鼠标及键盘操作
5. 元素等待【重点】
6. 下拉框选择
一、元素操作
2.1 方法
1). send_keys() # 输入方法
2). click() # 点击方法
3). clear() # 清空
2.2 提示:
1. 在输入方法之前一定要清空操作。
二、浏览器常用操作API
2.1 方法
1). driver.maximize_window() # 最大化浏览器
2). driver.set_window_size(w, h) # 设置浏览器大小 单位像素
3). driver.set_window_position(x, y) # 设置浏览器位置
4). driver.back() # 后退操作
5). driver.forward() # 前进操作
6). driver.refresh() # 刷新操作
7). driver.close() # 关闭当前主窗口(主窗口:默认启动哪个界面,就是主窗口)
8). driver.quit() # 关闭由driver对象启动的所有窗口
9). driver.title # 获取当前页面title信息
10). drive.current_url # 获取当前页面url信息
2.2 提示:
1. driver.title 和 driver.current_url 没有括号,应用场景:一般为判断上步操作是否执行成功。
2. driver.maximize_window() # 一般为我的前置代码,在获取driver后,直接编写最大化浏览器
3. driver.refresh() 应用场景,在后面的cookie章节会使用到。
4. driver.close()与driver.quit()区别:
close():关闭当前主窗口
quit():关闭由driver对象启动的所有窗口
提示:如果当前只有1个窗口,close与quit没有任何区别。
三、元素信息操作API
3.1 方法:
1). text 获取元素文本 如:driver.text
2). size 获取元素大小 如:driver.size
3). get_attribute 获取元素属性值 如:driver.get_attribute(“id”)
4). is_displayed 判断元素是否可见 如:element.is_displayed()
5). is_enabled 判断元素是否可用 如: element.is_enabled()
6). is_selected 判断元素是否被选中 如:element.is_selected()
3.2 提示:
1. text和size调用时 无括号
2. get_attribute一般应用场景:判断一组元素是否为想要的元素或者判断元素属性值是否正确
3. is_displayed、is_enabled、is_selected,在特殊应用场景中使用。
四、鼠标操作
4.1 为什么使用鼠标操作?
为了满足丰富的html鼠标效果,必须使用对应的方法。
4.2 鼠标事件对应的方法在哪个类中
ActionChains类—>导包 from selenium.webdriver.common.action_chains import ActionChains
4.3 鼠标事件常用的操作方法
1. context_click() # 右击
应用:context_click(element).perform()
2. double_click() # 双击
应用:double_click(element).perform()
3. drag_and_drop() # 拖拽
应用:drag_and_drop(source, target).perform
4. move_to_element() #悬停
应用: move_to_element(element).perform()
5. perform() # 执行以上事件方法
4.4 提示:
1. selenium框架中虽然提供了,右击鼠标方法,但是没有提供选择右击菜单方法,可以通过发送快捷键的方式解决(经测试,谷歌浏览器不支持)。
五、键盘操作
4.1 键盘对应的方法在Keys类中
包:from selenium.webdriver.common.keys import Keys
4.2 常用的快捷键:
CONTROL:Ctrl键
其他,请参考Keys底层定义的常亮
4.3 应用
组合键:element.send_keys(Keys.XXX, ‘a’)
单键:element.send_keys(Keys.XXX)
六、元素等待
6.1 为什么要设置元素等待
由于电脑配置或网络原因,在查找元素时,元素代码未在第一时间内被加载出来,而抛出未找到元素异常。
6.2 什么是元素等待
元素在第一次未找到时,元素等待设置的时长被激活,如果在设置的有效时长内找到元素,继续执行代码,如果超出设置的时长未找打元素,抛出未找到元素异常。
6.3 元素等待分类
1. 隐式等待
2. 显示等待
6.4 隐式等待
方法:driver.implicitly_wait(30) # 一般情况下设置30秒
特色:
1. 针对所有元素生效。
2. 一般情况下为前置必写代码(1.获取浏览器驱动对象;2. 最大化浏览器;3. 设置隐式等待)
6.5 显示等待
方法:WebDriverWait(driver,timeout=10, poll_frequency=0.5).until(lambda x:x.find_element_by_id("#user")).send_keys("admin")
参数:
timeout: 超时时间
poll_frequency:访问频率,默认0.5秒找一次元素
x: x为driver,它是WebDriverWait类将传入的driver赋值给类self._driver,until方法调用了self._driver;
提示:
1. WebDriverWait(driver,timeout=10, poll_frequency=0.5).until(lambda x:x.find_element_by_id("#user"))返回的一个元素。
6.6 显示等待与隐式等待区别:
1. 显示等待:针对单个元素生效
2. 隐式等待:针对全局元素生效
1.1 下拉选择框
1.2 弹出框
1.3 滚动条操作
1.4 frame表单切换
1.5 多窗口切换
1.6 窗口截图、验证码处理
一、下拉框
1.1 为什么单独使用下拉框?
1. 如果option选项没有value值的化,css定位或其他定位就不太方便。
1.2 如何使用Select类
操作:
1. 导包:from selenium.webdriver.support.select improt Select
2. 实例化:s = Select(element)
3. 调用方法:s.select_by_index()
1.3 提供哪些方法
1. select_by_index() # 通过下标定位
2. select_by_value() # 通过value值
3. select_by_visible_text() #显示文本
1.4 注意事项
1. 实例化select时,需要的参数为 select标签元素
2. 调用Select类下面的方法,是通过索引、value属性值、显示文本去控制,而不需要click事件
二、警告框
2.1 为什么要处理警告框?
如果页面由弹出框,不处理,接下来的将不生效。
2.2 对话框类型
1. alert # 警告框
2. confirm # 确认框
3. prompt # 提示框
2.3 如何处理
以上三种对话框,处理方法都一样。
步骤:
1. 切换到对话框
方法:driver.switch_to.alert
2. 处理对话框
alert.text # 获取文本
alert.accept() # 同意
alert.dismiss() # 取消
提示:无论以上哪个对话框,都可以使用取消、同意,因为调用的是后台的事件,根页面显示的按钮数量无关。
2.4 注意:
1. driver.switch_to.alert 方法适合以上三种类型对话框,调用时没有括号
2. 获取文本的方法,调用时没有括号 如:alert.text
3. 在项目中不是所有的小窗口都是以上三种对话框。
三、滚动条
3.1 为什么要操作滚动条
在web自动化中有些特殊场景,如:滚动条拉倒最底层,指定按钮才可用。
3.2 如何操作
第一步:设置操作滚动条操作语句
如:js = “window.scrollTo(0,10000)”
0: 左边距 --》水平滚动条
10000:上边距 -->垂直滚动条
第二步:调用执行js方法,将设置js语句传入方法中
方法:driver.execute_script(js)
3.3 说明
在selenium中没有直接提供定位滚动条组件方法,但是它提供了执行js语句方法,可以通过js语句来控制滚动条操作。
四、切换frame表单
提示:常用的frame表单有两种:frame、iframe
4.1 为什么要切换?
当前主目录内没有iframe表单页面元素信息,不切换,找不到元素。
4.2 如何切换?
方法:driver.switch_to.frame("id\name\element")
4.3 为什么要回到主目录
iframe或frame只有在主目录才有相关元素信息,不回到主目录,切换语句会报错。
4.4 如何回到主目录
方法:driver.switch_to.default_content()
4.5 提示:
1.切换frame时,可以使用name、id、iframe元素
五、多窗口切换
5.1 为什么要切换多窗口?
页面存在多个窗口式,seleniu默认焦点只会在主窗口上所有的元素,不切换切换窗口,无法操作除主窗口以外的窗口内元素
5.2 如何切换?
思路:获取要切换的窗口句柄,调用切换方法进行切换。
方法:
1. driver.current_window_handle # 获取当前主窗口句柄
2. driver.window_handles # 获取当前由driver启动所有窗口句柄
3. driver.switch_to.window(handle) # 切换窗口
步骤:
1. 获取当前窗口句柄
2. 点击链接 启动另一个窗口
3. 获取当前所有窗口句柄
4. 遍历所有窗口句柄
5. 判断当前遍历的窗口句柄不等于当前窗口句柄
6. 切换窗口操作
六、截屏
应用场景:失败截图,让错误看的更直观
方法:
driver.get_screenshot_as_file(imgepath)
参数:
imagepath:为图片要保存的目录地址及文件名称
如: 当前目录 ./test.png
上一级目录 …/test.png
扩展:
1. 多条用例执行失败,会产生多张图片,可以采用时间戳的形式,进去区分。
操作:
driver.get_screenshot_as_file(“…/image/%s.png”%(time.strftime(“%Y_%m_%d %H_%M_%S”)))
strftime:将时间转为字符串函数
注意:
%Y_%m_%d %H_%M_%S:代表,年 月 日 时 分 秒
七、验证码
7.1 什么是验证码?
一种随机生成信息(文字、数字、图片)
7.2 验证码作用
防止恶意请求
7.3 验证码处理方式
1. 去掉验证码(项目在测试环境、公司自己的项目)
2. 设置万能验证码(测试环境或线上环境,公司自己项目)
3. 使用验证码识别技术 (由于现在的验证码千奇百怪,导致识别率太低)
4. 使用cookie解决(推荐)
7.4 cookie 介绍:
生成:由服务器生成
作用:标识一次对话的状态(登录的状态)
使用:浏览器自动记录cookie,在下一条请求时将cookis信息自动附加请求
7.5 应用:
方法:
1. driver.get_cookies() # 获取所有的cookie
2. driver.add_cookies({字典}) # 设置cookie
步骤:
1. 打开百度url driver.get("http://www.baidu.com")
2. 设置cookie信息: driver.add_cookie({"name":"BDUSS","value":"根据实际情况编写"})
3. 暂停2秒以上
4. 刷新操作
注意:
1. 以上百度BDUSS所需格式为百度网站特有,别的网站请自行测试。
2. 必须进行刷新操作。
1. UnitTest框架基本使用
2. Fixture
3. 断言
4. Html测试报告
一、UnitTest框架
1.1 为什么使用UnitTest框架?
1. 批量执行用例
2. 提供丰富的断言知识
3. 可以生成报告
1.2 什么是UnitTest框架
python自带一种单元测试框架
1.3 核心要素
1). TestCase(测试用例)
2). TestSuite(测试套件)
3). TextTestRunner(以文本的形式运行测试用例)
4). TestLoader(批量执行测试用例-搜索指定文件夹内指定字母开头的模块) 【推荐】
5). Fixture(固定装置(两个固定的函数,一个初始化时使用,一个结束时使用))
TestCase:
说明:测试用例
步骤:
1. 导包 import unittest
2. 新建测试类并继承 unittest.TestCase
3. 测试方法必须以test字母开头
运行:
1. 运行测试类所有的测试方法,光标定位到类当前行右键运行
2. 运行单个测试方法:光标放到测试方法当前行。
TestSuite:
说明:测试套件
步骤:
1. 导包
2. 获取测试套件对象 suite = unittest.TestSuite()
3. 调用addTest()方法 添加测试用例
添加测试用例方法:
1. suite.addTest(类名("方法名称")) # 添加指定类中指定的测试方法
2. suite.addTest(unittest.makeSuite(类名)) # 添加指定类中所有已test开头的方法
TextTestRunner:
说明:执行测试套件方法
步骤:
1. 导包
2. 实例化后去执行套件对象 runner = unittest.TextTestRunner()
3. 调用run方法去执行 runner.run(suite)
TestLoader:
说明:
1. 将符合条件的测试方法添加到测试套件中
2. 搜索指定目录文件下指定字母开头的模块文件下test开始的方法,并将这些方法添加到测试套件中,最后返回测试套件
操作:
1. 导包
import unittest
2. 调用TestLoader()
写法1. suite = unittest.TestLoader().discover("指定搜索的目录文件","指定字母开头模块文件")
写法2. suite = unittest.defaultTestLoader.discover("指定搜索的目录文件","指定字母开头模块文件") 【推荐】
注意:如果使用写法1,TestLoader()必须有括号。
3. 执行测试套件
unittest.TextTestRunner().run(suite)
TestSuite与TestLoader区别:
共同点:都是测试套件
不同点:实现方式不同
TestSuite: 要么添加指定的测试类中所有test开头的方法,要么添加指定测试类中指定某个test开头的方法
TestLoader: 搜索指定目录下指定字母开头的模块文件中以test字母开头的方法并将这些方法添加到测试套件中,最后返回测试套件
二、fixture
说明:装置函数(setUp、tearDown)
级别:
1). 函数级别 def setUp() / def tearDown()
特性:几个测试函数,执行几次。每个测试函数执行之前都会执行 setUp,执行之后都会执行tearDwon
2). 类级别 def setUpClass() / def tearDownClass()
特性:测试类运行之前运行一次setUpClass 类运行之后运行一次tearDownClass
注意:类方法必须使用 @classmethod修饰
3). 模块级别:def setUpModule() / def tearDownModule()
特殊:模块运行之前执行一次setUpModule ,运行之后运行一次tearDownModule
提示:
无论使用函数级别还是类级别,最后常用场景为:
初始化:
1. 获取浏览器实例化对象
2. 最大化浏览器
3. 隐式等待
结束:
关闭浏览器驱动对象
三、断言
3.1 什么是断言?
让程序代替人为判断执行结果是否与预期结果相等的过程
3.2 为什么要断言?
自动化脚本执行时都是无人值守,需要通过断言来判断自动化脚本的执行是否通过
注:自动化脚本不写断言,相当于没有执行测试一个效果。
3.3 常用断言
1. self.assertEqual(ex1, ex2) #判断ex1 是否相等ex2
2. self.assertIn(ex1 ,ex2) # ex2是否包含ex1 注意:所谓的包含不能跳字符
3. self.assertTrue(ex) # 判断ex是否为True
3.4 断言练习
目标:tpshop登录
方法:
def setUp():
# 获取driver
# 打开url
# 最大化浏览器
# 隐式等待
def tearDown():
# 关闭浏览器驱动
def test_login_code_null():
# 根据业务流程编写
# ...
# 失败截图
3.5 扩展
断言两种实现方式
方式1:使用unittest框架中断言,详情请参考以上相关知识点。
方式2:使用python自带断言
1. assert str1 == str2 # 判断str1 是否与str2相等
2. assert str1 in str2 # 判断str2 是否包含str1
3. assert True/1 # 判断是否为True
四、参数化
4.1 为什么要参数化
解决冗余代码问题;
4.2 什么是参数化
说明:根据需求动态获取参数并引用的过程
4.3 参数化应用场景
场景:解决相同业务逻辑,不同测试数据问题。
4.4 应用:
1. 安装插件
通过命令:
安装:
pip install parameterized
验证:
pip show parameterized
通过pycharm:File-->setting-->Project 工程名称
2. 应用插件
1. 导包 from parameterized import parameterized
2. 修饰测试函数 @parameterized.expand([数据])
数据格式:
1. 单个参数:类型为列表
2. 多个参数:类型为列表嵌套元祖
3. 在测试函数中的参数设置变量引用参数值,注意:变量的数量必须和数据值的个数相同
一、跳过用例
分类:
1. 直接跳过
语法:@unittest.skip(说明)
场景:一般适合功能未实现完成用例
2. 条件满足跳过
语法:@unittest.skipIf(条件, 原因)
场景:一般判断条件满足,就不执行;如:达到指定版本,此功能失效;
提示:
以上两种方式,都可以修饰函数和类;
二、HTML测试报告
HTML报告:根据TextTestRunner改编而来
操作:
1. 导包
from xx.HTMLTestRunner import HTMLTestRunner
2. 定义测试套件
suite = unittest.defaultTestLoader.discover(“…/case”, pattern=“test*.py”)
3. 实例化HTMLTestRunner类,并调用run方法执行测试套件。
with open(报告存放路径, "wb") as f: #注意:生成html报告,必须使用wb,以二进制形式写入
# 实例化HTMLTestRunner类
HTMLTestRunner(stream=f).run(测试套件)
三、PO模式
版本:
v1:不采用任何模式(线性模型)
v2:采用测试框 unittest
v3:业务代码和页面对象进行
v4:实际中的po模式编写
案例:
tpshop登录
1. 账号不存在
2. 密码错误
问题:
v1:无法批量运行
v2: 业务脚本与页面对象没有分开
v3: 代码冗余量太大
PO介绍:
PO: page(页面) object(对象)
v4版本:
结构:
1. base(基类):page页面一些公共的方法;
# Base类
# 初始化方法
# 查找元素方法
# 点击元素方法
# 输入方法
# 获取文本方法
# 截图方法
注意:
1. 以上方法封装时候,解包只需1此,在查找元素解包;
2. driver为虚拟,谁调用base时,谁传入,无需关注从哪里来;
3. loc:真正使用loc的方法只有查找元素方法使用;
2. page(页面对象):一个页面封装成一个对象;
应用:继承base;
实现:
1. 模块名:page+实际操作模块名称 如:page_login.py
2. 页面对象名:以大驼峰方法将模块名抄进来,有下划线去掉下划线
3. 方法:涉及元素,将每个元素操作单独封装一个操作方法;
4. 组装:根据需求组装以上操作步骤;
3. scripts(业务层):导包调用 page页面
实现:
1. 模块:test+实际操作模块名称 如:test_login.py
2. 测试业务名称:以大驼峰方法将模块名抄进来,有下划线去掉下划线
3. 方法:
1. 初始化方法 setUp() 注:在unittest框架中不能使用def __init__()初始化方法;
# 实例化 页面对象
# 前置操作 如:打开等等
2. 结束方法 teardown
# 关闭驱动
3. 测试方法
# 根据要操作的业务来实现
扩展:
loc变量:类型为元组 ;*loc为解包;
扩展:
1. 线性驱动
2. 模块驱动
3. 数据驱动
一、数据驱动
1.1 什么是数据驱动?
说明:
1. 通过测试数据控制用例的执行,直接影响测试结果;
2. 数据驱动是最好结合PO+参数化技术使用;
1.2 数据驱动优点
将维护关注点放到测试数上,而不去关注测试脚本代码;
1.3 数据驱动常用的格式
1. JSON(重点)
2. XML
3. EXCEL
4. CSV
5. TXT
1.4 JSON介绍
1. 一种纯文本格式,后缀.json ;
2. 一种轻量级数据交换格式;(接口数据传递基本使用json格式)
3. 由键值对组成,和python的字典格式一模一样,不同之处在于(json是文本格式)
4. json语法:花括号包含键值对,键与值之间使用冒号(:)分隔, 键值对之间使用逗号(,)分隔;
1.5 json与字典转换
1). 字典转为json字符串
方法:dumps()
操作:
1. 导包
2. 调用dumps方法
3. 打印类型
注意:
使用dumps方法,而不是dump方法;
2) json字符串转字典
方法: loads()
操作:
1. 导包
2. 调用loads方法
3. 打印类型
注意:
1. 使用loads方法而不是load方法
2. 字符串中的键名必须使用双引号;
1.6 json的写与读
1). 写入json
方法:dump(写什么文件, 往那写)
操作:
1. 导包
2. 获取文件流f,并调用dump方法写入
注意:
1. 写入时模式 w
2. 写入的方法 dump() 而不是 dumps()
2). 读取json 【重点】
方法:load()
操作:
1. 导包
2. 获取文件流f,并调用load方法读取
注意:
1. 写入时模式 r
2. 写入的方法 load() 而不是 loads()
二、练习计算器
结构:
base
# 初始化方法
# 查找元素
# 点击
# 获取value属性方法封装
# 截图
page
# 点击数字
for n in num:
loc = By.ID, ““simple{}”.format(n)”
# 调用baes内点击方法
# 点击加号
# 点击等号
# 获取结果
# 组装业务方法
scripts
# 初始化方法
# 获取计算页面页面对象
# 获取driver
# 结束方法
# 关闭driver
# 测试加法方法
# 调用加法运算业务方法
# 断言
# 截图
drvier封装
类名
# 定义类变量
driver = None
@classmethod
# 获取driver方法
如果 cls.driver is None:
# 获取浏览器驱动对象
# 最大化
# 打开url 注:url建议写入配置文件中
返回 cls.driver
@classm3thod
# 关闭driver方法
如果 cls.driver:
cls.driver.quit()
# 注意此处一定要置空
cls.driver = None
读取json数据封装
1. 读取工具封装
# 导包
# 打开json获取文件流 并 调用load方法
2. 组装读取出来数据格式封装
预期格式:[(),()]
默认实际格式:{"":"","":""}
思路:
1. 新建空列表
2. 使用字典.values()方法获取所有的字典值;
3. 使用列表的.append((字典.get("键名")))
4. 返回 arrs
查找元素判断是否操作成功 思路封装
def base_if_success():
try:
self.base_find_element(loc, timeout=2)
return True
except:
return False
如何区分正向逆向用例
思路:在测试数据中添加一一个标识正向用例或逆向用例的标记: 如:True/False
步骤:
1. 调用登录方法(此登录方法中,只有输入用户名、输入密码、输入验证码、点击登录按钮) 切记:不要封装点击登录连接地址;
2. 判断是否正向用例:
# 判断安全退出是否存在
# 点击安全退出
# 点击登录连接地址
一、日志
1.1 什么是日志
说明:记录系统运行程序一些步骤,对一个事件(点击事件)也称为日志(Log)
1.2 特点
1. 调试程序
2. 定位跟踪bug
3. 根据日志,查看系统运行是否出错;
4. 分析用户行为,与数据统计
1.3 级别
1. debug # 调试级别
2. info # 信息级别
3. warning # 警告
4. error # 错误级别
5. critical # 严重
提示:
1. 开发常用以上 debug、info、warning、error
2. 测试常用级别:info、error
1.4 Logging基本使用
步骤:
1. 导包 如:import logging
2. 调用相应的级别方法,记录日志信息 logging.debug("debug...")
设置级别:
logging.basicConfig(level=logging.DEBUG)
提示:
1. 默认级别为:logging.WARNING
2. 设置级别时调用的是logging文件夹下面的常量,而不是调用的小写方法
3. 切记:设置级别以后,日志信息只会记录大于等于此级别的信息;
设置格式
fm = "%(asctime)s %(levelname)s [%(name)s] [%(filename)s (%(funcName)s:%(lineno)d] - %(message)s"
logging.basicConfig(level=logging.DEBUG, format=fm)
设置输入到文件
logging.basicConfig(level=logging.DEBUG, format=fm, filename="../log/log01.log")
1.5 logging 高级用法
1). 为什么要使用高阶用法???
1. 中文乱码
2. 无法同时输入到文件和控制台
2). logging组成
1. Logger 日志器
2. handler 处理器
3. formatter 格式器
4. filter 过滤器
3). 模块关系
日志器:提供了,记录日志的入口,如:log.info("")
处理器:真正将日志器内容发送到控制台还是文件或网络,都是处理器干的;每个日志器都可以添加多个不同的处理器
格式器:处理器可以设置不同的格式,就需要使用格式器
过滤器:处理器需要过滤日志信息,就需要设置过滤器;
日志器:
操作:
1. 导包 import logging
2. 调用方法获取logger对象 # 如: logging.getlogger()
3. 设置级别:logger.setlevel=logging.INFO
4. 调用添加处理器方法 logger.addHandler(处理器)
处理器:
类型:
1. 控制台处理器 StreamHandler()
2. 文件处理器 fileHandler() # 文件无限增大
3. 根据大小切割 RotatingFileHandler() 了解
4. 根据时间切割 TimedRotatingFileHandler() 掌握
获取:
sf = logging.StreamHandler()
TimedRotatingFileHandler()应用:
1. 导包: import logging.handlers
2. 实例化:th = logging.handers.TimedRotatingFileHandler(filename="日志文件保存的目录及文件名",
when='M',
interval="1",
backupcount=30)
1). when:时间单位
2). interval:时间间隔
3). backupcount:保留的备份数量
格式器:
获取:
fmt = "%(asctime)s %(levelname)s [%(name)s] [%(filename)s (%(funcName)s:%(lineno)d] - %(message)s"
fm = logging.Formatter(fmt)
将格式器添加到处理器中
控制台处理器.setFormatter(fm)
文件处理器.setFormatter(fm)
应用:
logger.info("日志信息")
logger.error("日志信息")
日志封装
# 定义获取日之类
# 定义类属性 logger = None
@classemethod
# 定义获取logger日志器的类方法
if cls.logger is None: # 判断类属性logger是否还是为空,如果为空,就执行以下操作
# 获取 日志器对象
# 设置日志器级别
# 获取控制台处理器
# 获取文件处理器
# 获取格式器
# 将格式器添加到处理器中
# 将处理器添加到日志器中
return 类属性logger
注意:
1. 以上条件无论是否成立,最后都会返回类属性logger;
2. 当第一次调用时,条件一定成立,将类属性logger设置不为空;
3. 当第二次以上调用时,永远返回第一次设置的类属性对象;
二、项目
2.1 自动化测试流程
1. 将功能用例转化自动化用例(在功能用例模板新增一列 是否自动化 )
2. 搭建自动化测试环境(本机依赖的环境:python、pycharm、浏览器、浏览器驱动、selenium、 parameterized)
3. 搭建自动化框架(po模式+数据驱动+log+报告)
4. 编写代码
5. 执行用例
6. 生成报告\分析log
2.2 自动化涉及的模块
1. 登录
2. 购物车
3. 订单
4. 支付
2.3 自动化测试结构
1. base(基类)
2. page(页面对象)
3. scripts(业务脚本)
4. tool(工具类)
5. data(存储测试数据文件)
6. log(日志)
7. image(失败截图)
8. report(测试报告)
2.4 base 公共方法封装实现
# 查找元素方法
# 点击元素方法
# 输入元素方法
# 获取元素文本方法
# 截图方法
# 判断元素是否存在方法封装
2.5 登录分析
0. 正确用户名+正确密码+正确验证码 预期:登录成功 并跳转到个人主页;
1. 用户名为空 + 正确密码 + 正确验证码 预期:用户名不能空!
2. 正确用户名 + 空密码 + 正确验证码 预期:密码不能为空!
3. 正确用户名 + 正确密码 + 空验证码 预期:验证码不能为空!
4. 用户名不存在 + 正确密码 + 正确验证码 预期:账号不存在!
5. 用户名格式不正确 + 正确密码 + 正确验证码 预期:账号格式不匹配!
6. 正确用户名 + 错误密码 + 正确验证码 预期:密码错误!
7. 正确用户名 + 正确密码 + 错误验证码 预期:验证码错误!