软件测试基础
软件测试的定义:
通过人工或工具对软件系统进行校验,检测是否满足需求文档的相关规定,并找出四级结果于预期结果的差异
软件测试的目的:
通过尽可能少的人力,物力,财力来查找并解决软件中的缺陷,降低产品失败的风险
软件测试的基本原则:
- 测试显示软件存在的缺陷
- 穷尽测试是不可能的
- 测试应该提早介入
- 缺陷集群性(2/8原则)
- 杀虫剂驳论
- 测试活动依赖与测试内容
- 没有错误就是好,这是谬论
软件测试的流程
需求分析:
- 目的:让产品,开发,测试,设计对需求理解达成一致,减少开发过程中由于理解不一致产生的bug,同时尽早发现需设计中存在的问题,尽早修改,降低修复成本。产品经理收集需求,召集开发,测试,设计与需求文档评审会议
- 有产品经理召集开发,测试,设计进行需求评审
- 注意事项:需要提前熟悉需求
- 需求包括需求文档,产品原型
测试计划及测试方案编写
-
目的:定义测试范围,测试方法,所需的资源,进度等,明确需要测试的产品项
需要覆盖的功能特性,需要执行的测试人物,每项任务的负责人,识别相关的风险
-
测试计划是由测试经理或者负责人编写
编写测试用例
测试用例评审
- 目的:针对所编写的测试用例进行查漏补缺
接口测试(可选)
- 编写完测试用例后,开发如果没有转测试,可以针对开发的后台服务器进行接口测试
执行测试用例
-
通过手工或者自动化执行测试用例,如果测试结果与用例的预期结果不符,那么就认为是BUG,也就是缺陷,需要将BUG通过缺陷管理工具进行记录,方便管理跟踪
-
自动化执行的用例就是针对当前版本的老的功能模块进行测试
提交测试报告
- 目的:在于总结测试阶段的测试过程及测试结果分析,描述系统是否打到需求,并依次作为是否上线的依据
- 测试报告内容:测试环境,测试模块,测试用例数,发现的BUG数,已解决BUG数,遗留BUG数,遗留风险,测试结论
- 测试报告完成之后需要发邮件通知相关的人员,开发,测试,运维,产品经理,项目基尼经理
产品上线
- 上线之后会做基本功能验证,一般是由产品经理去验证,产品上线的操作是由运维人员实施的
web自动化测试基础
- 软件自动化测试:由程序代替人工进行系统校验的过程
- 自动化测试能解决什么问题:
- 解决回归测试
- 解决压力测试
- 解决兼容性测试
- 提高工作效率,保证产品质量
自动化测试优缺点
- 优点
- 较少的时间内运行更多的测试用例
- 自动化脚本可重复运行
- 减少人为的错误
- 克服手工测试的局限性
- 误区
- 自动化测试可以完全的替代手工测试
- 自动化测试一定比手工测试厉害
- 自动化测试可以发掘更多的BUG
- 自动化测试可以适用于所有功能
自动化测试分类
- web自动化测试(*)
- 移动自动化测试
- 接口自动化测试
- 单元测试自动化测试
- 桌面的自动化测试
- 安全的自动化测试
- 嵌入式设备的自动化测试
web自动化测试的定义
- 由程序替代人工进行web系统校验的过程
适合做web自动化测试的项目(以下三个条件必须要全部达到才适合)
- 需求变动不频繁
- 项目周期长
- 项目需要回归测试
web自动化测试在什么阶段开始
- 功能测试完毕(手工测试完成之后),才能确定测试的操作步骤已经预期结果
web自动化测试所属分类
- 黑盒测试(功能测试)
- 白盒测试(单元测试)
- 灰盒测试(接口测试)
- web自动化测试属于黑盒测试(功能测试)
web自动化测试工具
主流的web自动化测试工具
- QTP:由惠普公司开发的商业工具,收费支持web,桌面应用程序的自动化
- Selenium *:免费开源,只支持web自动化
- Robot framework:是一款自动化测试平台
selenium特点
- 开源软件
- 款平台:支持不同的操作系统,windows linux macos
- 支持多浏览器:firefox chrome opera Ie safari
- 支持多语言:python java C#
- 成熟稳定,功能强大
web自动化环境搭建
所需要的工具
- python
- pycharm编辑器
- 基于python的selenium
- 浏览器驱动
- 要把你要测试的浏览器驱动放入到python根目录中
- 浏览器
一般的测试代码
-
导入selenium工具包
-
from selenium import webdriver #webdriver 代表的就是浏览器驱动
-
-
实例化浏览器对象
-
driver = webdriver.Chrome() #实例化谷歌浏览器
-
-
打开测试网站
-
driver.get(“http://www.baidu.com”)
-
-
等待3秒
-
time.sleep(3)
-
-
退出浏览器
-
driver.quit()
-
Selenium-API操作
元素定位
-
元素:由标签头和标签尾以及中间包含的内容组合在一起就是一个元素
-
元素定位可以通过元素的信息(属性)或者是元素的层级结构来进行元素定位
-
selenium定位元素的8种方式
-
id
- 定位方法:driver.find_element_by_id(id).send_keys()
-
name
- 定位方法:driver.find_element_by_name(name)
-
class_name
- 定位方法:driver.find_element_by_class_name() 有多个class的时候只要一个
-
tag_name
- 定位方法:driver.find_element_by_tag_name() 默认是定位第一位,可以使用数组下标来访问
-
link_text
- 定位的内容是a标签的内容文本
- 定位方法:driver.find_element_by_link_text()
-
partail_link_text
- 定位的内容是a标签的内容部分文本
- 定位方法:driver.find_element_by_partial_link_text()
-
xpath
- 定位方法:driver.find_element_by_xpath(xpath表达式)
- 路径定位的下标是从1开始的,根目录是/,因为在html标签的最前面还有一个顶级标签就是/
- 绝对路径就是从/开始的,相对路径就是从//开始的
- 元素定位://tag_name[@attribute=“value”] (通过class来定位时,需要写上所有的class值,一个也不能少)
- XPath-延伸:
- //*[text()=“xxx”]
- //*[contains(@attribute, ‘xxx’)]
- //*[starts-with(@attribute, ‘xxx’)]
-
css
- 定位速度要比xpath块,因为xpath要扫描整个文档,速度比较慢
- 推荐使用css进行元素定位,但是工作当中还是使用xpath用的比较多,xpath支持下标选择,而且常用的css选择器是不支持下标的
- 定位方法:
- driver.find_element_by_css_selector(css_selector)
- css_selector表示的是css选择器的表达式
- css常用的选择器
- id选择器
- 表达式:#id
- class选择器
- 表达式:.class
- 有多个的时候,只使用class的一个来选择
- 元素选择器
- 表达式:标签名
- 不支持下标,不推荐使用
- 元素属性选择器
- 表达式:[attribute=‘value’],也可以不使用引号
- 层级选择器
- 父子层级关系
- form>p>.class
- 隔代层级关系
- form .class
- 父子层级关系
- css扩展
- tag_name[attribute^=‘value’] 属性值以value开头的
- tag_name[attribute$=‘value’] 属性值以value结尾的
- tag_name[attribute*=‘value’] 属性值包含value的
- id选择器
-
driver.find_element(上面8种方式,表达式)
- 需要导入by包:from selenium.webdriver.common.by import By
-
元素操作
- click() 点击元素
- send_keys(value) 模拟输入
- clear() 清除文本
浏览器常用方法
- maximize_window() 最大化窗口
- set_window_size(width,height) 设置浏览器窗口大小
- set_window_position(width,height) 设置浏览器的坐标位置
- refresh() 刷新浏览器
- back() 回退操作
- forward() 前进操作
- close() 关闭浏览器当前页面
- qiut() 退出浏览器
- title 获取浏览器窗口标题
- current_url 获取浏览器窗口路径
获取元素信息
- size 获取元素大小
- text 获取元素文本
- get_attribute(“attribute”) 获取元素属性值
- is_display() 判断元素是否可见
- is_enable() 判断元素是否可用
- is_selected() 判断元素是否被选中
鼠标操作
需要导入:from selenium.webdriver import ActionChains
- 实例化鼠标对象
- action = ActionChains(driver) 实例化鼠标对象
- action .context_click(获取元素的变量) 鼠标右击事件
- action.double_click(获取的元素对象) 鼠标双击事件
- action.move_to_element(获取的元素对象) 鼠标悬停事件
- action.drag_and_drop() 鼠标拖动事件
- action .perform() 执行鼠标事件
键盘操作
导包:from selenium.webdriver.common.keys import Keys
- send_keys(Keys.BACK_SPACE) 删除键
- send_keys(Keys.SPACE) 空格键
- send_keys(Keys.TAB) 制表键
- send_keys(Keys.ESCAPE) 回退键
- send_keys(Keys.ENTER) 回车键
- send_keys(Keys.CONTROL, ‘a’) 全选键
- send_keys(Keys.CONTROL, ‘c’) 复制键
- send_keys(Keys.CONTROL, v‘’) 粘贴键
元素等待
- 隐式等待
- 定义:等待页面加载完成后,定位元素时,如果能够找到该元素则直接返回该元素,如果找不到该元素,那么每隔一段时间再去找该元素(默认时间是0.5s)当超最长的设置时间,还没有找到该元素,则抛出NoSuchElementtException
- 实现方法:driver.impliclity_wait(timeout)
- 隐式等待设置,对后续元素定位都有效
- 显示等待
- 定义:定位元素时,如果能够找到该元素则直接返回该元素,如果找不到该元素,那么每隔一段时间再去找该元素(默认时间是0.5s)当超最长的设置时间,还没有找到该元素,则抛出TimeOutException
- 实现方法:WebDriverWait(driver,10,1).unitl(lamdba x:x.find_element(By.ID,‘value’))
- 返回的是一个元素对象
- 工作中建议使用显示,为了方便调用,会提前封装方法,方便调用
- 强制等待
- 适用对象:要等待的元素不需要进行元素定位,但是该元素跟要操作的元素有业务的关联,一定要等待元素加载完成之后,才能对操作的元素操作成功
- 当需要获取的元素的文本信息是通过后台接口获取并渲染到元素中,此时需要加强制等待才能准确的拿到对应的文本内容
- 强制等待就是暂停代码执行time.sleep(等待时间)
下拉选择框,弹出框,滚动条操作
-
select类是selenium为操作select标签特殊封装的
from selenium.webdriver.support.select import Select
-
实现步骤:
-
通过select类实例化下拉选择框
- select = Select(element) element表示的是下拉选择框元素对象
通过select对象来选择选项
-
通过下拉选择框的索引来选择选项,索引是从0开始的
select.select_by_index(index)
-
通过下拉选择框的value属性值选择选项
select.select_by_value(value)
-
通过下拉选择框中选项的文本内容选择选项
select.select_by_visible_text(value)
-
-
弹出框的操作
-
三种弹出框:alert confirm prompt
-
操作步骤:
-
获取弹出框对象
alert = driver.switch_to.alert 这个操作要在已经点击出现弹出框
-
处理弹出框的三种方式
alert.text 获取弹出框的内容
alert.accept() 接收弹出框选项,相当于点击,弹出框的确定按钮
alert.dismiss() 取消弹出框选项,相当于点击弹出框的取消按钮
-
-
窗口切换
-
原因:新打开的浏览器窗口如果不做窗口切换,无法对新打开的窗口进行相关操作
selenium是通过窗口句柄来实现对窗口的定位及切换的
-
实现方法:
- 获取当前窗口句柄:driver.current_window_handle
- 获取所有窗口句柄:driver.window_handles 返回的是一个列表
- 切换窗口句柄: driver.switch_to_window(handle) handle表示的窗口句柄
frame切换方法
- 实现方法:driver.switch_to.frame(element) 切换到指定的iframe
- driver.switch_to.default_content() 恢复到默认首页
- 总结:
- 要进入的iframe有几层,就需要切换几次
- 如果进入到同一个层级的iframe中去,一定要先恢复到首页去
- 不管当前在那个iframe层级中,只要调用一次恢复默认首页的方法就可以回到默认首页
窗口截图
- 实现方法:driver.get_screenshot_as_file(filename)
- 作用:当窗口自动化代码出现错误的时候,可以通过截图进行截图保存错误信息
- 文件截图保存的必须是png结尾
验证码
- 验证码处理方式
- 去掉验证码
- 设置万能验证码
- 验证码识别技术(通过python-tesseract来识别图片类型验证码,识别率不是00%)
- 记录cookie (通过记录cookie来跳过登陆操作,没有使用cookie的网站就不能使用)
- cookie常用方法
- get_cookies() 获取网站所有的cookie
- get_cookie() 获取某一个cookie
- add_cookie(cookie_dict) 添加cookie
UnitTest框架
什么是unitTest框架
- UnitTest是python自带的单元测试框架,用它来做单元测试框架
- 能够生成测试报告
TestCase
-
定义测试类,需要继承unittest.TestCase
class TestAdd(unittest.TestCase)
-
定义测试方法,方法名称必须是以test开头
def test_add(self)
pass
-
TestCase运行,鼠标在那个方法上点击运行,就测试那个方法,如果是在类名中点击测试,那就是测试所有的方法
TestSuite测试套件
- 实例化套件
- suite = unittest.TestSuite()
- 在suite中添加测试用例
- suite.addTest(className(“methodName”)) 添加一个类里面某个方法
- suite.addTest(unittest.makeSuite(className)) 添加一个类里面所有的方法
- runner = unittest.TextTestRunner() runner.run(suite)实例化运行器
TestLoader
- 实现方法:unittest.TestLoader().discover(test_dir, pattern=“test*.py”)
Fixture
- 方法级别的Fixture(定义在测试类里面)
- def setUp(self) 初始化操作
- def tearDown(self) 销毁操作
- 类级别的Fixture(定义在测试类里面)
- def setUpClass(cls) 初始化操作 最上面需要@classmethod装饰器
- def tearDownClass(cls) 销毁操作 最上面需要@classmethod装饰器
- 模块级别Fixture(定义在类外面)
- def setUpModule(cls) 初始化操作
- def tearDownModule(cls) 销毁操作
断言常用方法
- assertTure(result) 为true通过
- assertFalse(result) 为false通过
- assertEqual(result,预期结果) 预期结果符合通过
- assertNotEqual(result,预期结果) 预期结果不符合通过
- assertIsNone(result) 预期结果为none,通过
- assertIsNotNone(result) 预期结果不为none 通过
- assertIn(str(result,‘字符串’) 字符串结果包含结果 通过
- assertNotIn(str(result), ‘字符串’) 字符串结果不包含结果,通过
参数化实现
-
借助parameterized模块
- 安装:pip install parameterized
使用parameterized装饰器传入数据
@parameterized.expand(data)
跳过测试
- 针对那些不再使用的方法跳过测试
- 跳过指定的测试方法或测试类
- @unittest.skip(“reason“)
- @unittest.skipIf(“resason”, msg)
生成HTML测试报告
-
HTMLTestRunner安装方式
- 把HTMLTestRunner.py复制到site-packages目录下
-
使用方法:
import time
from HTMLTestRunner import HTMLTestRunner
import unittest
from test_skip_02 import TestAdd
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(TestAdd))
filename= ‘./report/report{}.html’.format(time.strftime(“%Y%m%d%H%M%S”))
with open(filename, ‘wb’) as f:
runner = HTMLTestRunner(stream=f, title=“web自动化”,description=“windows-chrome-v2.0”)
runner.run(suite)