回顾测试理论基础
单元测试基础知识
什么是单元测试
单元测试流程、测试计划
测试策略设计、实现
单元测试 - 执行
HTML 报告生成
1 软件测试分类
目标
回顾测试理论知识-测试分类
**1.**测 试分类 代码可见度上-划分分类:
- 黑盒测试
- 灰盒测试
- 白盒测试
1.1 黑盒测试
作用:是针对整个产品系统进行的测试,验证系统是否满足需求规格的定义,及软件产品的正确性和性能等
是否满
足其需求规格的要求。
1.2 灰盒测试
作用:是介于白盒测试与黑盒测试之间的一种测试,灰盒测试多用于集成测试阶段,不仅关注输出、输入的
正确性
,同时也关注程序内部的情况。
1.3 白盒测试
作用:是通过程序的源代码进行测试而不使用用户界面。这种类型的测试需要从代码内部在算法,路径,条件等等中的缺点或者错误,进而加以修正。
2单元测试基础
1.1 案例
- 组装一台电脑,选购各种配件 (CPU 、主板、内存、硬盘、电源 ) 等,组装完成后,电脑运行启动无反应。
- 编写一个程序,编写完成程序运行不起来 ( 程序由 N 个不同功能函数和语句组成 )
1.2 问题 - 无法确定各配件哪个有问题。
- 无法确定那个函数或语句出现问题。
**2.**什么是单元测试?
概念:单元测试是针对程序的最小单元来进行正确性检验的过程。
单元:一个单元可能是单个程序、类、对象、方法(函数)等。
2.1优点:
- 减少 BUG
- 快速定位 BUG
- 提高代码质量
- 减少调试时间
2.2缺点:
- 周期时间长
4 2. 耗费资源 - 能力要求高
3. 单元测试 - 总结 - 概念
- 优点
- 缺点
5
如何进行单元测试
目标
- 了解单元测试流程
如何进行单元测试?
单元测试流程
- 单元测试 - 计划
- 确定要测试代码范围
- 评估标准 ( 确定被测代码的覆盖率 )
- 测试策略 - 设计
- 拿到开发代码进行调整 ( 可独立执行 )
- 测试策略 - 实现
- 根据调整好的代码 - 画流程图
- 根据流程图画流图 - 确定复杂度、路径
- 根据复杂度和路径确定测试用例 ( 测试数据 )
- 单元测试 - 执行
- 使用测试框架 (UnitTest) 编写单元测试用例
- 测试用例 ( 代码 ) 和测试数据分离
- 生成测试报告
**1.单元测试-**计划
概念:对要测试代码的确定以及这些被测代码的评估标准、优先级等说明
- 确定单元测试范围 ( 那些代码要做单元测试 )
- 评估标准 -( 被测代码的逻辑覆盖率 )
1.1如何确定单元测试代码范围?
依据:二八原则 (20% 的代码中隐藏了 80% 的缺陷 )
如何确定**20%**代码?
- 频率:使用频率高的代码段;
- 复用性: ( 是否已被复用 )
1). 全新
2). 部分复用
3). 全部复用 - 开发人员:
1). 技术
2). 业务 - 复杂度:业务逻辑复杂度 ( 一般认为圈复杂度在 7 级以上代码包括在 20% 的代码中 )
如何确定圈复杂度等级?
圈复杂度:在学习测试策略实现时讲解
附录**-**测试范围汇总格式
1.2评估标准
如何确定逻辑覆盖率?
-
语句覆盖率
-
分支覆盖率
-
条件覆盖率
-
路径覆盖率
-
分支- 条件覆盖率
练习 1
提示用户输入一个数,如果该数大于 0 则加 1 ,否则减 1 ;
代码:#提示用户输入一个数,如果该数大于0则加一,如果小于0则减一
num=int(input("请输入一个数:"))
if num>0:
num=num+1
elif num<=0:
num=num-1
print("num的值为:"+str(num))
流程图 :
流程图
说明:使用统一规定标准图形,描述程序运行的具体步骤
目的:
- 确定覆盖率
- 根据流程图画流图 (流图--> 测试策略实现时学习)
什么是语句覆盖率?
语句:非分支非判断的代码
练习1测试数据
- 输入 3=2/3
- 输入 0=2/3
- 输入 -2=2/3
语句覆盖率**-**总结
- 语句
- 计算方式:被覆盖语句 / 总语句
分支覆盖率
分支:判断语句的分支; 如 :if 判断有两个分支
练习1分支覆盖率测试数据
本题有两个分支
- 输入 3=1/2
- 输入 0=1/2
- 输入 -2=1/2
分支覆盖率**-**总结
- 分支
- 计算方式:覆盖分支 / 总分支数
条件覆盖率
条件:结果为 true 或 false
练习 2
输入用户名和密码,如果用户名为:admin, 密码为: 123456 ,输出验证成功;否则输出验证失败;
代码:
#输入用户名和密码,如果用户名为:admin,密码为:123456,输出验证成功;否则输出验证失败;
username=input("请输入用户名:")
password=input("请输入密码:")
#注意input输入的是字符串类型
if username=="admin" and password=="123456":
print("验证成功")
else:
print("验证失败")
流程图:
练习 2 分析
- 条件个数
练习 2 测试数据 - 用户名: admin 密码: 123456
- 用户名: zhangsan 密码: 123456
- 用户名: admin 密码: 456789
练习 3
输入两个数 a,b ,如果 a>5 and b<5 执行语句 3 ;否则 elif a==5 or b<10 执行语句 4 ;否则执行语句 5
代码:
流程图:
练习 3 分析 - 条件个数
练习 3 测试数据 - a=3,b=6
- a=6,b=3
- a=6,b=6
练习 4
9 输入用户名和密码:
如果 username= "admin" and password="123456" 执行语句 3; 否则执行语句 4
如果 username= "zhangsan" and password="654321" 执行语句 5 ;否则执行语句 6
练习 4 分析 - 条件个数
练习 4 测试数据 - 用户名: admin 密码: 123456
- 用户名: zhang 密码: 123456
路径覆盖率
路径:从开始到结束的过程
分析练习 2 路径 - 路径个数
分析练习 3 路径 - 路径个数
练习 3 路径覆盖数据 - a=6,b=3
路径覆盖率 - 总结 - 路径概念
- 计算方式:覆盖路径 / 全部路径
- 路径和分支区别
分支 - 条件覆盖率
10 说明:分支和条件的组合
练习 2 测数据 分支 - 条件覆盖率 - 用户名: admin 密码: 123456
分析练习 2 分支 - 条件覆盖率 - 分支个数
- 条件个数
- 分支条件个数
练习 3 测试数据 分支 - 条件覆盖率 - a=6,b=6
练习 3 分析 分支 - 条件覆盖率 - 分支个数
- 条件个数
- 分支条件个数
练习 4 汇总 - 语句覆盖率
- 分支覆盖率
- 条件覆盖率
- 路径覆盖率
- 分支条件覆盖率
提示:
练习 4 :路径有 4 条,但有一条永远不可成立,所以路径为 3 条;
练习 4 测试数据 - 用户名: admin 密码: 123456
11 1.3 测试策略设计、实现
目标 - 了解单元测试 - 测试策略
1. 什么是单元测试策略?
概念:针对单元测试选择测试的一种方式
2. 单元测试策略 - 方式 - 自上向下
- 自下向上
- 孤立策略
2.1 策略 自上向下
方式:从最上层函数往下开始逐层测试
案例 1
两个函数 ( 求和、求减 ) ,求和函数内调用求减函数;
案例 1 分析 - 编写求和函数
- 编写求减函数
- 在求和函数内调用求减函数
- 调用求和函数
案例 1 问题
12 1. 我们只想测试求和函数不测求减函数该如何做?
打桩
概念:打桩就是模拟编写一个我们需要引用的函数
提示:一般我们只模拟写个函数名,直接返回相应的结果即可
示例:
def fun_1(self):
return true
自上向下 - 总结: - 方式
- 打桩 ( 模拟调用的函数 )
- 缺点 ( 成本高 )
2.2 策略 自下向上
方式:从最底层函数往上开始逐层测试
自下向上 - 总结: - 方式
- 缺点 ( 周期长 )
2.3 策略 孤立策略
方式:选择需要进行测试的函数进行测试
孤立策略 - 总结: - 方式
- 【推荐使用】
- 优点:选择重要的代码进行测试
3. 测试策略实现
13 3.1 什么是测试策略实现?
概念:把我们选定的代码,转向流程图、流图及用例的过程
3.2 测试策略实现如何操作? - 将测试代码转换成流程图
- 根据流程图转换为流图
案例 2
函数 (test001) 判断参数 a, 如果 a>0 ,输出语句 1 ;
案例 2 流程图
什么是流图?
概念:表达程序业务逻辑的复杂度一种示意图
构成:
- 圈:判断条件、语句块 ( 一条或多条语句 ) 两者都圈
- 线:箭头指向的线,用来连接圈和圈的指向
流图的目的? - 确定单元的复杂度级别
- 确定测试用例
备注 : 路径的个数为复杂度的级别 ( 一条路径为 1 个复杂度级别 )
14 案例 2 流图
测试用例 模板
案例 2 总结
- 路径: 2 (1-2-3,1-3)
- 复杂度: 2
- 用例个数: 2
案例 3
函数 (test002) 判断参数 a,b; 如果 a>0 and b<10 输出语句 1 ;否则输出语句 2 ;
代码 :
流程图 :
流图:
案例 3 总结 - 复杂度
- 路径明细
思考?
15 如果把案例 3 的条件 a>0 and b<10 换成 条件 1 or 条件 2 那么复杂度是多少?
案例 4
输入两个数,如果两个数同时为大于 0 小于 10 ,那么就进行求和运算;否则判断两个数是否同时大于等于 10 小
于 20 那么
就进行求减运算,否则输入错误;
代码:
流程图:
流图:
案例 4 总结 - 路径数:
- 路径明细:
- 复杂度:
案例 5 while 循环
使用 while 循环求 1-10 相加之和;
代码:
流程图:
流图:
案例 5 总结 - 路径数:
- 路径明细:
- 复杂度:
案例 6
提示输入三角形三条边 , 进行判断三角形类型 ( 等边、等腰、普通 ) 并进行提示,否则提示不是三角形;
提示:
三角形:两边之和大于第三边;
16 等腰三角形:两条边相等
等边三角形:三条边相等
案例 6 步骤分析 - 代码:
- 自定义函数
- 判断是否为三角形
- 判断是否为等边三角形
- 非等边三角形继续判断是否为等腰三角形
- 如果不是等腰三角形,输出普通三角形
- 流程图
- 流图
- 用例
总结 - 单元测试计划
- 测试策略设计
- 测试策略实现
17 1.4 单元测试 - 执行
目标 - 回顾 UnitTest 框架使用
- 基于 UnitTest 测试三角形案例
- 在 UnitTest 框架中使用数据分离
什么是单元测试执行?
概念:通过单元测试框架对要进行测试代码的实践过程
1. 练习 1 - 通过 Python 语言编写一个运算的类 (Calc) ,类中包含两个函数:
- add(self,a,b) 返回 a+b 之和
- sub(self,a,c) 返回 a-c 之差
提示:通过练习 1 ,我们先简单复习下 UnitTest 框架的使用
1.1 练习 1 步骤分析
- 新建 Calc 类
- 在 Calc 类中新建 add 函数
- 在 Calc 类中新建 sub 函数
- 调用对象中方法
1.2 练习 1 单元测试 - 导包 UnitTest 、 Calc 类
- 新建单元测试类 Test01( 集成 unitTest.TestCase)
- 新建 testAdd() 函数
1). 导入 Calc 类中的 add 函数
18 2). 添加断言 - 新建 testSub() 函数
1). 导入 Calc 类中的 sub 函数
2). 添加断言 - 执行测试
1). unittest.main()
1.3 总结 - 导包
- setUp 函数作用
- tearDown 函数作用
- 断言
- 运行测试函数
1.4 问题 - 练习 1 我们数据直接写入代码中,如果数量庞大,我们需要频繁改动数据或复制冗余代码进行实现数据测
试目的。 - 做不到数据分离 ( 代码和数据分开 ) ,不便维护;
参数化
概念:根据需求动态获取数据并进行赋值的过程
2. 参数化 - 方式 - XML 格式( 1 )
- CSV 格式( 2 )
- JSON 串 ( 3 )
- TXT 文本( 4 )
提示:括号内为推荐使用优先级,从小到大 ;1-2 为扩展了解, 3-4 建议重点了解
3. XML 是什么?
概念: XML 是一种标记语句,很类似 HTML 标记语言;后缀 .xml
19 3.1 XML 与 HTML 区别?
XML 是传输和存储数据,焦点在数据; HTML 是显示数据,焦点在外观;
3.2 XML 格式是什么?
<?xml version="1.0" encoding="UTF-8"?>
<book category=" 面授 ">
<title> 单元测试 </title>
<author>XST</author>
<year>2008</year>
<price>39.95</price>
</book> - 必须有 XML 声明语句: <?xml version="1.0" encoding="UTF-8"?>
- 必须要有一个根元素,如: <book>
- 标签大小写敏感
- 属性值用双引号
- 标签成对
- 元素正确嵌套
- 标签名可随意命名 , 但有以下限制
- 不能以数字或者标点符号开始参
2 )不能以字符 "xml" (或者 XML 、 Xml )开始 - 名称不能包含空格
3.3 需求
对三角形案例单元测试使用 XML 格式进行参数化
3.4 操作步骤
- 编写 XML 数据文件
- 编写读取 XML 模块函数
- 单元测试模块中引用 XML 读取函数
- 执行
3.5 重点分析 - 导入 XML 包 from xml.dom import minidom
- 加载解析 dom=minidom.parse(filename)
20 3. 获取对象 root=dom.documentElement - 获取子元素 aas=root.getElementsByTagName(one)[0]
- 获取子元素值 aas.getElementsByTagName(two)[0].firstChild.data
3.6 XML- 总结 - 读取方式
- 什么是 XML
- XML 与 HTML 区别
- XML 编写格式
- 缺点:不适合大量参数化数据时使用
4. CSV 格式
概念: CSV 是一种以逗号做分割的表格格式 ; 后缀 .csv
4.1 使用 CSV 实现三角形案例参数化 - 操作步骤 - 创建 CSV 文件
- 编写 CSV 读取模块函数
- 单元测试 - 引用 CSV 读取函数
- 执行
4.2 重点分析 - 导包 import csv
- 打开 csv 文件
with open("../Data/sjx.csv","r",encoding="utf-8") as f:
lines=csv.reader(f)
4.3 CSV- 总结 - 读取方式
- 生成 CSV 文件方式
- 编码
21 5. 什么是 JSON ?
概念:一种轻量级数据交换格式;后缀名 .json
提示:
接口测试一般使用 JSON 为接口传递数据规范格式,所以我们有必要对如何获取 JSON 数据做个了解;
5.1 JSON 格式
格式: {"name":" 张三 ","age":28}
提示:由键值对组成 , 健名和值之间使用分号 (:) 分割,多个键值对之间使用逗号 (,) 分割
5.2 使用 JSON 实现三角形案例参数化 - 操作步骤 - 编写 JSON 文件
- 编写 JSON 读取模块函数
- 单元测试 - 引用 JSON 读取函数
- 执行
5.3 难点分析 - 导入 JSON 包( import JSON )
- 打开 JSON 文件并解析
with open('../DataXML/sjx.json','r',encoding='utf-8') as f:
file=json.load(f)
5.4 JSON- 总结 - JSON 概念
- JSON 格式
- 如何导入 JSON 包
- 如何加载 JSON
6. TXT 文本
概念:一种纯文本格式 ; 后缀名 .txt
6.1 TXT 文本优点:
22 1. 编写测试数据方便 - 使用模块函数读取时便捷
6.2 使用 TXT 实现三角形案例参数化 - 操作步骤 - 创建 txt 文本并写入测试数据
- 编写读取 txt 模块函数
- 单元测试 - 引用 JSON 读取函数
- 执行
6.3 难点分析 - 如何读取 txt 文本?
with open(r'../DataXML/ 三角形 .txt','r',encoding='utf-8') as f: - 如何去除行尾 /n 换行符?
line.strip()
6.4 TXT 总结 - TXT 文本读取
- 去除行尾回车符 (/n)
7. 参数化 - 总结 - XML
- CSV
- JSON
- TXT
23 HTML 报告生成
目标
对单元测试生成 HTML 报告进行简单回顾
1. 如何生成 HTML 报告?
1.1. 导入 HTML 报告模板 模板
HTMLTestRunner.py
1.2 编写生成 HTML 模块
导入 unittest 包
import unittest
导入 HTMLTestRunner 模板包
from UnitTest.Day02.ReadData.HTMLTestRunner import HTMLTestRunner
导入时间包
import time
定义测试模块路径
dirpath='.'
disconver=unittest.defaultTestLoader.discover(dirpath,pattern='test*.py')
if name=='main':
存放报告的文件夹
report_dir='../TestReport'
报告名称含时间,时间格式
now=time.strftime("%Y-%m-%d %H_%M_%S")
报告完整路径 + 名称
report_name=report_dir+'/'+now+'result.html'
打开报告写入结果
with open(report_name,'wb')as f:
runner=HTMLTestRunner(stream=f,title="UnitTest Report-SJX",description='Tes
t Case Report')
runner.run(disconver)
1.3 生成报告示例图
24 25