第一章 软件测试基础知识精要(上)
1.1 从“用户登录”测试谈起
1.1.1 功能测试用例
1.1.2 更多的测试用例
1.1.3 功能性需求与非功能性需求
对显式功能性需求的验证
对隐式功能性需求的验证
安全性
性能
兼容性
1.1.4 测试的不可穷尽性
时间成本和经济成本。
基于风险驱动的模式(优先测试高风险)
1.2 设计“好的”测试用例
1.2.1 “好的”测试用例的定义
“好的”测试用例一定是一个完备的集合,它能够覆盖所有等价类以及各种边界值,而与能否发现缺陷无关。
1.2.2 “好的”测试用例具备的特征
整体完备性:能够完全覆盖测试需求。
等价类划分的准确性:对于每个等价类都能保证只要其中一个输入测试通过,其他输入也一定测试通过。
等价类集合的完备性:所有可能的边界值和边界条件都已经正确识别。
1.2.3 常用测试用例的设计方法
等价类划分方法(常用)
将所有可能的输入数据划分成若干个子集,每个子集中任意一个输入数据对于揭示程序中潜在错误都具有同等效果。
边界值分析方法(常用)
该方法是对等价类划分方法的补充。选取输入、输出的边界值进行测试。
错误推测方法(常用)
基于对被测试软件系统设计的理解、过往经验以及个人直觉,推测出软件可能存在的缺陷,从而有针对性地设计测试用例的方法。
因果图方法
判定表驱动分析方法
正交实验设计方法
功能图分析方法
场景设计方法
形式化方法
扩展有限状态机方法
1.2.4 “好的”测试用例的设计方法
从软件功能需求出发,全面地、无遗漏地识别出测试需求。这将直接关系到测试用例的测试覆盖率。
对于识别出的每个测试需求点,需要综合运用等价类划分方法、边界值分析方法和错误推测方法来全面地设计测试用例。
1.2.5 测试用例设计的其他经验
只有深入理解被测试软件的架构,才能设计出有的放矢的测试用例集,去发现系统边界以及系统集成上的潜在缺陷。
必须深入理解被测试软件的设计也实现细节,深入理解软件内部的处理逻辑。
需要引入需要覆盖率和代码覆盖率来衡量测试执行的完备性,并以此为依据来找出遗漏的测试点。
1.3 单元测试的基础知识
1.3.1 单元测试的定义
单元测试是指对,对软件中的最小可测试单元在与程序其它部分相隔离的情况下进行检查和验证的工作,这里最小可测试单元通常是指函数或类。
1.3.2 单元测试的最佳实践
代码的基本特征:对数据进行分类处理。
代码产生错误的原因:分类遗漏或分类错误
1.3.3 单元测试用例详解
驱动代码、桩代码和Mock代码
驱动代码
被测函数
桩代码
Mock代码
桩代码的编写
Mock代码(记录驱动代码是否调用及调用次数)和桩代码(模拟其它模块功能)的异同。
1.3.4 单元测试在实际项目中的最佳实践
只在底层模块或者核心模块的测试中采用单元测试
需要确定单元测试框架的造型,这和开发语言直接相关。Java用JUnit和TestNG,C/C++用CppTest和Parasoft C/C++ test
框架选型完成后,还需要对桩代码框架和Mock代码框架进行选型。
为了能够衡量单元测试的代码覆盖率,通常还需要引入计算代码覆盖率的工具。Java用JaCoCo,JS用Istanbul
需要对单元测试的执行、代码覆盖率的统计和持续集成的流水线进行集成。
1.4 自动化测试的原始驱动力和使用场景
1.4.1 自动化测试的基本概念
自动化测试的本质是先编写一段代码,然后测试另一段代码。
1.4.2 自动化测试的优势和劣势
优势
解放测试工程师到更有价值的工作;提升回归效率;更好的利用无人值守时间;高效实现某些手工测试无法完成或代价巨大的测试;保证每次测试的一致性。
劣势
不能取代手工测试;比手工测试脆弱;开发工作量远大于单次的手工测试,1:5原则;发现缺陷少;不稳定的测试用例的实现比没有用自动化测试更糟糕;初期用例开发效率通常很低;业务测试专家和自动化测试专家是两批人;自动化测试开发人员必须具备一定的编程能力。
1.4.3 自动化测试的使用场景
需求稳定、不会频繁变更的场景。
研发和维护周期长,需要频繁执行回归测试的场景。
需要在多种平台上重复运行相同测试的场景。
通过手工测试无法实现或者手工测试成本太高的测试项目。
被测软件的开发较为规范并且能够保证系统可测试性的场景。
测试人员已经具备一定编程能力的场景。
1.5 软件开发各阶段的自动化测试技术
1.5.1 单元测试的自动化测试技术
测试用例框架代码的自动生成
部分测试输入数据的自动生成
桩代码的自动生成
被测代码的自动静态分析
测试覆盖率的自动统计与分析
单元测试用例的自动执行
1.5.2 代码级集成测试的自动化技术
代码级集成测试是指将已经开发完的软件模块放在一起测试。
自动化技术与单元测试技术相同。
现在互联网企业基本上不会去做代码级集成测试。
1.5.3 Web Service测试的自动化技术
Web Service测试,主要指SOAP API和REST API这两类API测试,最典型的是采用SoapUI或Postman等类似的工具进行API测试。
1.5.4 GUI测试的自动化技术
对于传统Web浏览器的GUI自动化测试,采用Selenium。
对于移动端原生应用的GUI自动化测试,采用Appium,它对iOS环境集成了XCUITest,对Android环境集成了UIAutomator和Espresso。
1.6 测试覆盖率
1.6.1 需求覆盖率
测试对需求的覆盖程度。
1.6.2 代码覆盖率
至少执行了一次的条目数占整个条目数的百分比
行覆盖率(Statement Coverage),最常用
函数覆盖率(Function Coverage)
判定覆盖率(Decision Coverage),用于度量程序中的每一个判断的分支是否都被测试到了。
条件覆盖率(Condition Coverage),判断的每个条件的可能取值至少满足一次,用于度量判断的每个条件的结果是否都测试到了。
条件/判断覆盖率(Condition/Decision Coverage),同时满足条件覆盖率和判定覆盖率。
修改条件/判断覆盖率(Modified Condition/Decision Coverage, MC/DC)是一个要求最高的覆盖率指标。
1.6.3 代码覆盖率的价值
找出潜在的遗漏测试用例,并针对性的进行补充,同时还可以识别出代码中那些由于需求变更等原因造成的不可用的废弃代码。
1.6.4 代码覆盖率的局限性
高的代码覆盖率不一定能保证软件的质量,但是低的代码覆盖率一定不能保证软件的质量。
1.6.5 关于代码覆盖率的报告
Java的JaCoco
1.6.6 代码覆盖率工具的实现技术
注入
源代码
字节码
离线注入
即时注入
插入
替换
Java代理
类加载器
第二章 软件测试基础知识精要(下)
2.1 高效撰写软件缺陷报告
2.1.1 缺陷标题
对缺陷的概括性描述,通常采用“在什么情况下发生了什么问题”的模式。
清晰、简洁、具体;描述问题本质;缺陷标题不宜过长。
2.1.2 缺陷概述
提供更多概括性的缺陷本质与现象的描述;缺陷的其他延展部分。
2.1.3 缺陷影响
缺陷引起的问题对用户或者对业务的影响范围以及严重程度。
优先级:由开发经理判断;严重程序:由产品经理判断。
2.1.4 环境配置
环境配置通常按需描述,通常只描述那些重现缺陷的环境敏感信息。
2.1.5 前置条件
测试步骤开始前应该处在的状态。
2.1.6 缺陷重现步骤
操作步骤通常是从用户角度出发来描述的,每个步骤都应该是可操作并且是连贯的。
2.1.7 期望结果和实际结果
当描述期望结果时,需要说明应该发生什么。
当描述实际结果时,需要说明发生了什么。
2.1.8 优先级和严重程度
优先级:缺陷必须被修复的紧急程度。
严重程度:因缺陷引起的故障对软件产品的影响程度。
2.1.9 变通方案
临时绕开当前缺陷而不影响产品功能的解决问题的方式。
2.1.10 根原因分析
RCA(Root Cause Analysis),定位出问题的根本原因。
2.1.11 附件
Attachment,为缺陷的存在提供必要的证据支持,截图、测试用例日志、服务器端日志、GUI测试的执行视频等。
2.2 以终为始,做好测试计划
2.2.1 测试测试计划会怎么样
不知道具体的测试范围,以及应该采取的具体测试策略。
很难预估工具量和所需要的测试工程师数量。
测试的整体进度不可控。
整个项目对潜在风险的抵抗能力弱。
2.2.2 测试范围
描述被测对象以及主要的测试内容。明确“测试什么”和“不测试什么”。
2.2.3 测试策略
需要明确“先测试什么后测试什么”和“如何来测试”这两个问题。
功能测试、性能测试、兼容性测试、接口测试、集成测试、安全测试、容量验证、安装测试、故障恢复测试等
2.2.4 测试资源
测试人员和测试环境。明确“谁来测试”和“在哪里测试”
2.2.5 测试进度
描述各类测试的开始时间、所需工作量、预计完成时间,并以此为依据来推算最终产品的上线和发布时间是否可以满足。
行为驱动开发(Behavior-Driven Development, BDD)模式或者测试驱动开发(TDD)
2.2.6 测试风险预估
需求变更、开发延期、发现重大缺陷和人员变动是引入项目测试风险的主要原因。
2.3 软件测试工程师的核心竞争力
2.3.1 两个实际面试案例
作为测试人员必须要深入理解业务,但是业务知识不等同于测试能力。
测试开发岗位的核心是“测试”,“开发”的目的是更好的服务于测试,看重的是对测试的理解,以及在此基础上设计、开发帮助测试人员提高效率并解决实际问题的能力。
2.3.2 传统测试工程师的核心竞争力
测试策略设计能力
测试要具体执行到什么程度?
测试需要借助于什么工具?
如何运用自动化测试以及自动化测试框架?以及如何选型?
测试人员资源如何合理分配?
测试进度如何安排?
测试风险如何应对?
测试用例设计能力
无论对于什么类型的测试,都能设计出高效地发现缺陷、保证产品质量的优秀测试用例的能力。
快速学习能力
对不同业务需求和功能的快速学习与理解能力。
对于测试新技术和新方法的学习与应用能力。
学习新开源工具时,建议直接看官方文档。
学习新内容时,一定要理解其原理,而不是只停留在表面的、简单的操作和使用上。
探索性测试思维
测试工程师在执行测试的过程中不断学习被测系统,同时结合自己的猜测和逻辑推理,整理和分析出更多针对性的测试关注点。
缺陷分析能力
对于已经发现的缺陷,结合发生错误的上下文以及后台日志,可以预测或者定位缺陷的原因,甚至可以明确指出出错的代码行,由此可以大幅度缩短缺陷的修复周期。
根据已经发现的缺陷,结合探索性测试思维,推断同类缺陷存在的可能性,并由此找出所有相关潜在缺陷。
可以对一段时间内所发生的缺陷类型和趋势进行合理分析,由点到面预估整体质量的健康状态,能够对高频缺陷类型提供系统性的预防措施,并以此来调整后续的测试策略。
自动化测试技术
自动化测试技术不绑定被测对象。
自动化测试技术需要测试工程师具备一定的代码编写能力。
良好的沟通能力
对接产品经理和项目经理,以确保需求的满足和项目整体质量的达标。
和开发人员不断地沟通、协调,确保缺陷及时修复与验证。
2.3.3 测试开发工程师的核心竞争力
测试系统需求分析能力
能够站在测试架构师的高度,识别出测试基础架构的需求,提出提高效率的方法。
更宽广的知识面
不仅需要和开发工程师打交道,还要和CI/CD、运维工程师有紧密的联系。还要了解更高级别的测试架构部署和生产架构部署,还必须对采用的各种技术非常熟悉。
2.4 软件测试工程师需要掌握的非测试知识
2.4.1 迷你版的系统架构师
2.4.2 网站架构的核心知识
2.4.3 容器技术
2.4.4 云计算技术
2.4.5 DevOps思维
2.4.6 前端开发技术
2.5 互联网产品的测试策略设计
2.5.1 研发流程的不同决定了测试策略的不同
2.5.2 传统软件产品的测试策略——金字塔模型
单元测试、API测试、GUI测试。
2.5.3 互联网产品的测试策略——菱形模型
重量级API测试、轻量级GUI测试、轻量级单元测试
第三章 GUI自动化测试精要
3.1 从0到1:GUI自动化测试初探
3.1.1 示例:构建一个Selenium自动化测试用例
pytest + selenium + allure
3.1.2 Selenium的实现原理
Selenium 1.0(弃用)
Selenium 2.0
当使用Selenium 2.0启动Web浏览器时,后台会同时启动基于WebDriver Wire协议的Web服务作为Selenium的远程服务器,并将其与浏览器绑定。绑定完成后,远程服务器就开始监听客户端的操作请求。
执行测试时,测试用例会作为客户端,将需要执行的页面操作请求以HTTP请求的方式发送给远程服务器。该HTTP请求的正文以WebDriver Wire协议规定的JSON格式来描述需要浏览器执行的具体操作。
远程服务器接收到请求后,会对请求进行解析,并将解析结果发给WebDriver,由WebDriver实际执行浏览器的操作。
WebDriver可以看作直接操作浏览器的原生组件,所以搭建测试环境时,通过需要先下载浏览器对应的WebDriver。
Selenium 3.0
向下兼容2.0;JDK至少1.8;Firefox也需要下载WebDriver;开始支持Edge浏览器;支持IE的最低版本为IE9
3.2 效率为王:测试脚本和测试数据的解耦
3.2.1 测试脚本和测试数据的解耦
如果在测试脚本中硬编码测试数据,测试脚本的灵活性会非常低。另外,对于那些具有相同页面操作而只是测试输入数据不同的用例来说,就会存在大量重复的代码。
3.2.2 数据驱动测试
DDT(Data Driver Test)pytest+ddt
将数据保存到文件(csv,xls,json,yaml)或数据库中。
数据包括:测试输入数据、测试验证结果数据、测试逻辑分支的控制变量。
3.3 效率为王:页面对象模型(Page Object)
3.3.1 早期GUI测试脚本的结构
开发几个GUI自动化测试会觉得很高效,但是开发成百上千个GUI自动化测试会很痛苦
3.3.2 基于模块化思想实现GUI测试用例
把一些通用的操作集合打包成函数。GUI自动化测试脚本由“流水账”过渡到了“可用的脚本片段”。
3.3.3 基于页面对象模型实现GUI测试用例
页面对象模型的核心理念是,以页面(Web页面或者原生应用页面)为单位来封装页面上的控件以及控件的部分操作。而测试用例(理确切的说是操作函数),基于页面封装对象来完成具体的界面操作,最典型的模式是“XXXPage.YYYComponent.ZZZOperation”。
3.4 更接近业务的抽象:让自动化测试脚本更好地描述业务
3.4.1 操作函数的粒度把控
往往以完成一个业务流程为主线,抽象出其中的”高内聚低耦合“的操作步骤集合,操作函数就由这些操作步骤集合构成。
3.4.2 衔接两个操作函数之间的页面
前序操作函数完成后的最后一个页面,必须是后续操作函数的第一个页面。
3.4.3 业务流程抽象
基于操作函数的更接近于实际业务的更高层次的抽象方式。
3.5 过不了的坎:GUI自动化过程中的测试数据
3.5.1 基于API调用创建测试数据
3.5.2 基于数据库操作创建测试数据
3.5.3 综合运用API调用和数据库操作创建测试数据
3.5.4 实时创建测试数据
测试过程中,创建测试数据。
3.5.5 事先创建测试数据
测试前,创建测试数据
3.5.6 实时创建测试数据和事先创建测试数据的互补
3.6 GUI测试还能这么玩
3.6.1 自动生成页面对象
”自动化你的自动化“
商用自动化工具(如UFT)已经支持。
免费的Katalon Studio已经提供了类似的页面对象库管理功能。
3.6.2 自动生成GUI测试数据
根据GUI输入数据类型,以及对应的自定义规则库自动自动测试输入数据。
对于需要组合多个测试输入数据的场景。
3.6.3 无头浏览器简介
无头浏览器(Headless Browser)是一种没有界面的浏览器。
3.6.4 Headless Chrome与Puppeteer的使用
Puppeteer是一个Node库,提供高级别的API封装,这些API会通过Chrome DevTools Protocol与Headless Chrome的交互达到自动化操作的目的。
3.7 精益求精:提高GUI测试稳定性的关键技术
3.7.1 非预计的弹出对话框
通过自动进入”异常场景恢复模式“来解决。
3.7.2 页面控件属性的细微变化
通过”模糊匹配“实现。
3.7.3 被测系统的A/B测试
在测试脚本内部对不同的被测版本做分支处理。
3.7.4 随机的页面延迟造成控制识别失败
使用重试机制。用例级别、步骤级别、页面级别和业务流程级别。
3.7.5 测试数据问题
3.8 眼前一亮:带你玩转GUI自动化的测试报告
3.8.1 早期基于视频的GUI测试报告
报告比较大,分析测试报告时,需要结合测试用例以及服务器端的日志信息。
3.8.2 开源GUI测试框架的测试报告实现思路
页面截图
3.8.3 全球化GUI测试报告的创新设计
全球化测试是指,同一个业务在全球各个国家(地区)都有自己的网站。
横向报告是一个地区的业务测试顺序截图。
测试执行和缺陷管理系统交互。
3.9 真实的战场:大型全球化项目中GUI自动化测试策略的设计
3.9.1 大型全球化电商网站的前端模块划分
按照业务模块划分,用户管理模块、商户订单管理模块、商品管理模块等。
从代码库角度,划分为独立的代码库和公共组件代码库。
3.9.2 大型全球化电商网站的GUI自动化测试策略设计
前端组件测试:对那些自定义的组件进行全面的测试。基于Jest开展单元测试,并考量JavaScript的代码覆盖率指标。
前端模块测试:测试用例需要覆盖该模块的所有业务逻辑以及相关的功能测试点。
端到端测试:从终端用户的视角,以黑盒的方式使用网站的端到端测试。
3.9.3 大型全球化电商网站的GUI自动化测试脚本管理
将各个模块的页面对象和业务流程脚本放在各自的代码库中,并引入页面对象和业务流程脚本的版本管理机制。
第四章 移动应用测试技术
4.1 移动应用的种类和特点
4.1.1 Web应用
本质上就是网页。
4.1.2 原生应用
apk或ipa
4.1.3 混合应用
在原生移动应用中嵌入了WebView,然后通过WebView来访问网页。
4.2 移动应用测试方法概论
移动端的测试除了使用的测试框架不同以外,测试设计本身和GUI测试相似。
4.2.1 Web应用的测试
4.2.2 原生应用的测试
4.2.3 混合应用的测试
4.2.4 移动应用的测试难点
移动端的测试效率总是低于Web端的测试效率。测试框架原因
难以全面覆盖种类繁多的测试设备。
移动端的测试很难达到Web端测试的粒度。用户手势(捏拉、拖拽等)
移动端测试出现不可预料的场景的可能性更大。
移动端测试的网上资料不系统、不全面。
4.3 移动应用的专项测试
4.3.1 安装测试
4.3.2 卸载测试
4.3.3 特殊操作测试
手势操作
4.3.4 交互测试
测试应用与其他系统的交互是否正常。调用摄像头、导入相册等。
4.3.5 通知测试
测试应用推送的通知是否能在通知栏正常显示。
4.3.6 交叉事件测试
又叫中断测试,是指在应用执行过程中,其他事件或者应用中断了当前应用执行的测试。有电话、有短信、有闹铃等。
4.3.7 兼容性测试
确保应用在各种终端设备、各种操作系统版本、各种组件版本、各种屏幕分辨率、各种网络环境下功能的正确性。
4.3.8 流量测试
可借助tcpdump,wireshark,fiddler等。
4.3.9 耗电量测试
4.3.10 弱网络测试
4.3.11 边界测试
对移动应用在一些临界状态下的行为功能的验证和测试。内存、存储空间、飞行模式、操作系统时间不正确等。
4.4 移动应用测试工具:Appium使用入门
4.4.1 移动应用的自动化测试需求
4.4.2 iOS开发环境的搭建
4.4.3 Android开发环境的搭建
4.4.4 Appium测试环境的搭建
4.4.5 Appium Inspector的使用
4.5 Appium实战(iOS篇)
4.5.1 基于iOS开发第一个原生应用的测试用例
4.5.2 基于iOS开发第一个Web应用的测试用例
4.5.3 在iOS真机上执行Web应用测试
4.5.4 在iOS真机上执行原生应用测试
4.6 Appium实战(Android平台)
4.6.1 基于Android模拟器的Web应用测试
4.6.2 基于Android真机的Web应用测试
4.6.3 Web应用的测试:温故而知新
4.6.4 底层自动化驱动引擎
4.6.5 基于Android模拟器的原生应用测试
4.6.6 基于Android真机的原生应用测试
4.6.7 原生应用的测试:温故而知新
4.7 Appium的实现原理
4.7.1 Appium服务器
本质上,Appium服务器是一个Node.js应用,接受来自Appium客户端的请求,解析后通过WebDriver协议和设备端上的代理打交道。
4.7.2 Appium客户端
Appium客户端其实就是测试代码运行端。使用对应语言的客户端将基于Json Wire协议的操作指令发给Appium服务器。
4.8 企业级移动应用测试框架的设计思路与实践
4.8.1 移动应用测试框架的设计思路
如果企业已有比较成熟的Web端测试框架,就要尽量将移动端的测试功能集成到原有框架中。
尽量保持与已有框架相似的设计。
底层使用主流的测试框架。
采用面向对象的思想来设计测试框架。
接口对不对平台(iOS和Android)要统一化封装。
要有完善的日志和测试报告。
4.8.2 移动应用测试框架的实现与实践
4.9 搭建企业级移动测试私有云的实践
4.9.1 基于Selenium Grid的移动测试私有云
Selenium Grid是一个能够让测试脚本并行运行在不同的平台以及不同的浏览器上的一个框架。
4.9.2 基于Open STF的移动测试私有云
Open STF(Smartphone Test Farm)是一套基于Node.js编写的远程管理Android智能移动设备的工具。
4.10 移动应用云测试服务简介
4.10.1 Sauce Labs
4.10.2 Testin
中国开发团队开发的一个基于真实设备的测试云平台。
4.10.3 MTC
移动测试中心(Mobile Testing Center, MTC)是百度提供的移动应用自动化测试服务平台。
第五章 API自动化测试技术
5.1 从0到1:API测试初探
5.1.1 API测试的基本步骤
准备测试数据
通过API测试工具发起对被测API的请求
验证响应
5.1.2 基于Spring Boot构建被测API
5.1.3 使用cURL
5.1.4 使用Postman
5.2 复杂场景的API测试
5.2.1 被测业务操作由多个API调用协作完成
通过网络监控的手段,捕获单个前端操作所触发的API调用序列。
5.2.2 API测试过程中的第三方依赖
启用Mock Server来代替真实的API。
5.2.3 异步API测试
异步API是指,调用API后会立即返回结果,但是实际任务并没有真正完成,而需要稍后查询或者回调API。
测试异步调用是否成功。
测试异步调用的业务逻辑处理是否正确。
5.3 API自动化测试框架的技术演进与创新
5.3.1 早期基于Postman的API测试
5.3.2 基于Postman和Newman的API测试
5.3.3 基于代码的API测试
Java的OkHttp和Unirest
Python的http.client和Requests
5.3.4 自动生成API测试代码
基于Postman的Collection生成基于代码的API测试用例。
5.3.5 当响应结果发生变化时的自动识别
首先在API测试框架里引入一个内建数据库,推荐采用非关系型数据库(如MongoDB),然后用这个数据库记录每次调用的请求和响应的组合。当下次发送相同的请求时,API测试框架会自动和上次的响应做差异检测,对于变化的字段给出警告。
通过规则配置设立一个”白名单列表“,把那些动态值的字段排除在外。token值、会话ID、时间戳等。
5.4 微服务模式下的API测试
5.4.1 单体架构
将所有业务场景的表示层、业务逻辑层和数据访问层放在同一个工程中,经过编译、打包并部署在服务器上。
问题
灵活性差。再小的内容,也需要打包整个应用。
可扩展性差。高并发场景下,无法以模板为单位扩展容量。
稳定性差。任何模块有问题,都可能导致应用整体的不可用。
可维护性差。随着业务复杂性的提升,代码的复杂性也直线上升。
5.4.2 微服务架构
在微服务架构下,一个大型复杂软件由一系统相互独立的微服务组成。各个微服务运行在自己的进程中,开发和部署都没有依赖。
特点
每个服务运行在其独立的进程中,开发中采用的技术栈也是独立的。
服务间采用轻量级通信机制进行沟通,通过是基于HTTP的RESTful API。
每个服务都围绕着具体的业务进行构建,并且能够独立开发、独立部署、独立发布。
对运维提出了非常高的要求,促进了CI/CD及DevOps的发展与落地。
5.4.3 微服务架构下的测试挑战
过于庞大的测试用例数量
微服务之间的耦合关系。
5.4.4 基于消费者契约的API测试
服务T的使用者是确定的,只有服务A和服务B需要考虑,如果可以测试服务A和服务B对服务T的所有可能的调用方式,那么就一定可以保证服务T的质量。
如果能够找出这样的集合,并以此作为服务T的测试用例,那么只要这些测试用例100%通过,服务T的质量就有保证了。
这样的测试用例集合其实就是,服务T可以对外服务的契约,我们把这个测试用例的集合称为”基于消费者契约的API测试“,这里服务A和服务B就是消费者的角色。
可以通过解析API网关的日志得到每个服务的契约。
5.4.5 微服务测试的依赖解耦和模拟服务
利用获取的契约处理。
5.4.6 代码实例
第六章 代码级软件测试技术基础与进阶
6.1 代码级测试的基本理念与方法
代码错误
功能层面错误
性能层面错误
有特征的错误
无特征的错误
时间性能上的错误
空间性能上的错误
语法特征错误
边界行为特征错误
经验特征错误
算法错误
部分算法错误
6.1.1 常见的代码错误类型
6.1.2 代码级测试常用方法
静态方法和动态方法。
6.2 静态测试方法
6.2.1 人工静态方法
代码走查
结对编程
同行评审
6.2.2 自动静态方法
6.2.3 使用自动静态方法的实例
C语言的splint
6.3 动态测试方法
6.3.1 人工动态方法
6.3.2 自动动态方法
基于代码自动生成边界测试用例并执行来捕捉潜在的异常、崩溃和超时的测试方法。
6.4 代码静态扫描工具Sonar的使用
6.4.1 基于Sonar的实例
6.4.2 SonarLint的使用
6.5 单元测试框架TestNG的使用
TestNG是一个基于Java的经典开源自动化测试框架。NG,Next Generation,下一代。
6.5.1 TestNG的基本使用
6.5.2 TestNG的高级用法
@BeforeClass/@AfterClass和@BeforeMethod/@AfterMethod
异常测试(抛出异常)
超时测试,在@Test注解中添加timeout参数。
依赖测试,在@Test注解的dependsOnMethods参数来指定依赖方法和方法的执行顺序。
6.6 代码覆盖率工具JaCoCo的使用
6.6.1 JaCoCo简介
JaCoCo是一个开源的代码覆盖率工具。它针对的开发语言是Java。
多尺度覆盖率计数器
指令覆盖率(C0覆盖率)
分支覆盖率(C1覆盖率)
圈复杂度覆盖率
行覆盖率
方法覆盖率
类覆盖率9
6.6.2 JaCoCo的使用
第七章 性能测试基础
7.1 不同视角下的软件性能与性能指标
对于Web类应用和手机端应用,一般以终端用户感受到的端到端的响应时间来描述系统的性能。
对于 非交互式的应用,如电信和银行后台处理系统,对性能关注的是事件处理的速度,以及单位时间的事件吞吐量
软件系统性能
终端用户
系统运维人员
软件设计开发人员
性能测试人员
7.1.1 终端用户眼中的软件性能
用户进行业务操作时的响应时间,包括系统响应时间和前端展示时间。
7.1.2 系统运维人员眼中的软件性能
除了包括单个用户的响应时间外,软件性能还包括大量用户并发访问时的负载,以及可能在更大负载情况下的系统健康状态、并发处理能力、当前部署的系统容量、可能的系统瓶颈、系统配置层面的调优、数据库的调优,以及长时间运行的稳定性和可扩展性。
7.1.3 软件设计开发人员眼中的软件性能
与性能相关的设计和实现细节,几乎涵盖了软件设计和开发的全过程。
包括算法设计、架构设计、性能实践、数据库、软件性能的可测试性
7.1.4 性能测试人员眼中的软件性能
既要能够准确把握软件的性能需求,又要能够准确定位造成性能低下的因素和根源,并提出相应的解决方案。
7.1.5 并发用户数
业务层面。实际使用系统的用户总数。
服务器层面。同时向服务器发送请求的数量。
7.1.6 响应时间
应用系统从请求发出到客户端接收到最后一字节的数据所消耗的时间。
分为前端展示时间和系统响应时间两部分。
7.1.7 系统吞吐量
对于性能测试来说,通常用每秒的请求数,每秒的页面数和每秒的字节数来衡量吞吐量。
7.1.8 并发用户数、响应时间、系统吞吐量之间的关系
当系统并发用户数较少时,系统的吞吐量也低,系统处于空闲状态,我们往往把这个阶段称为”空闲区间“。
当系统整体负载并不是很大时,随着系统并发用户数的增长,系统的吞吐量也会线性增长,我们往往把这个阶段称为”线性增长区间“。
随着系统并发用户数的进一步增长,系统的处理能力逐渐趋于饱和,因此每个用户的响应时间会逐渐变长。相应地,系统的整体吞吐量并不会随着并发用户数的增长而继续线性增长。我们往往把这个时间点称为系统的”拐点“。
随着系统并发用户数的增长,系统处理能力达到过饱和状态。此时,如果继续增加并发用户数,最终所有用户的响应时间会变得无限长。相应地,系统的整体吞吐量会降为零,系统处于被压垮的状态。我们往往把这个阶段称为”过饱和区间“。
7.2 常用的性能测试与应用领域
7.2.1 常用的7种性能测试
后端性能测试(Back-end Performance Test)
性能指标除了包括并发用户数、响应时间和系统吞吐量外,还包括各类资源的使用率,如系统CPU占用率、内存使用率、磁盘I/O和网络I/O等,应用级别以及JVM级别的各类资源使用率。
场景设计方式
基于性能需求目标的测试验证
探索系统的容量,并验证系统容量的可扩展性测试
前端性能测试(Front-end Performance Test)
前端性能测试方法雅虎前端团队总结的7大类
减少HTTP请求次数。
减少DNS查询次数。
避免页面跳转
使用内容分发网络(Content Delivery Network,CDN)
通过Gzip压缩传输文件。
代码级性能测试(Code-level Performance Test)
在单元测试阶段就对代码的时间性能与空间性能进行测试和评估,以防止底层代码的执行效率总量在项目后期才被发现。
压力测试(Load/Stress Test)
不断对系统施加压力,验证系统处于或长期处于临界饱和阶段的稳定性以及性能指标,并试图找到系统处于临界状态时影响性能的主要瓶颈。
配置测试(Configuration Test)
观察系统在不同配置下的性能表现。
并发测试(Concurrence Test)
在同一时间调用后端服务,在一段时间内观察被调用服务在并发情况下的行为表现,旨在发现诸如资源竞争、资源死锁之类的问题。
可靠性测试(Reliability Test)
系统在常规负载模式下长期运行稳定性。
7.2.2 性能测试的四大应用领域
能力验证
主要验证”某系统能否在A条件下具有B能力“。
能力规划
如何才能使系统达到要求的性能和容量。
性能调优
解决性能测试过程中发现的性能瓶颈问题。
缺陷发现
通过性能测试的各种方法来发现诸如内存泄露、资源竞争、不合理的线程锁和死锁等问题。
7.3 后端性能测试工具原理与行业常用工具简介
7.3.1 后端性能测试和后端性能测试工具之间的关系
完整的后端性能测试应该包括性能需求获取、性能场景设计、性能测试脚本开发、性能场景实现、性能测试执行、性能结果分析、性能优化和再验证。其中后端性能测试工具主要在性能测试脚本开发、性能场景实现、性能测试执行这3个步骤中发挥作用。
7.3.2 后端性能测试工具和GUI自动化测试工具的区别
第一个区别是模拟用户行为的方式。浏览器点击与接口调用。
第二个区别是测试的执行方式。单用户与并发用户
7.3.3 后端性能测试工具的原理
基于客户端与服务器端的通信协议,构建模拟业务操作的虚拟用户测试脚本。
以多线程或多进程的方式并发执行虚拟用户测试脚本。
在施加测试负载的整个过程中,除了需要监控和收集被测试系统的各种性能数据外,还需要监控被测系统中各个服务器的各种软/硬件资源。
将系统监控器收集的所有信息汇总为完整的测试报告。
7.3.4 后端性能测试场景设计和具体内容
后端性能测试场景设计
测试负载组成
虚拟用户测试脚本
各个虚拟用户测试脚本的并发数量
总的并发用户数
负载策略
加压策略
减压策略
最大负载运行时间
延时策略
资源监控范围定义
操作系统级别的监控指标
应用服务器的监控指标
数据库服务器的监控指标
缓存集群的监控指标
终止方式
测试脚本出错时的处理方式
负载熔断机制
负载产生规划
压力产生器数量
网络带宽要求
7.3.5 业内主流的后端性能测试工具
LoadRunner、JMeter、NeoLoad等。
7.4 前端性能测试工具原理
7.4.1 Performance Timing API
一个支持WebKit内核浏览器中记录页面加载和解析过程的关键时间点的机制,它可以详细记录每个页面资源从开始加载到解析完成这一过程中具体操作发生的时间,既根据开始和结束时间戳就可以计算出这个过程所花的时间。
7.4.2 Profile工具
Profile是Chrome和Firefox等标准浏览器提供的一种用于测试页面脚本运行时系统内存和CPU资源占用情况的API。
7.4.3 页面埋点计时
通过页面埋点计时的方式来统计每部分代码的运行时间。
7.4.4 资源加载时序图
这种方法可以粗粒度地分析浏览器的所有资源文件请求耗时和文件加载顺序。
第八章 性能测试实战
8.1 前端性能测试工具WebPagetest
8.1.1 WebPagetest功能简介
可以提供全方位的前端性能量化指标,包括页面的加载时间、首字节时间、渲染开始时间、最早页面可交互时间、页面中各种资源的字节数、后端请求数量等。
自动给出被测页面性能优化水平的评价指标。
能提供Filmstrip视图、Waterfall视图、Connection视图、Request详情视图和页面加载视图。
8.1.2 使用WebPagetest测试某网站的首页
8.1.3 前端性能评估结果评分分析
First Byte Time
用户发起页面请求到接收到服务器返回的第一个字节所花费的时间。
Keep-alive Enabled
服务器配置,要求每次请求使用已经建立好的链接。
Compress Transfer
为文本资源启用压缩。
Compress Images
对图像文件也进行压缩。
渐进式JPEG。打开文件后,会先显示整个图片的模糊轮廓,随着扫描次数的增加,图片会变得越来越清晰。
Cache static content
浏览器缓存静态资源。
Effective use of CDN
CDN(Content Delivery Network,内容分发网络)的基本原理是采用各种缓存服务器,将这些缓存服务器分布到用户访问相对集中的地区的网络供应商机房内,当用户访问网站时,利用全局负载技术将用户的访问指向距离最近的、正常工作的缓存服务器,由这个缓存服务器直接响应用户请求。
8.1.4 其他前端性能指标解读
Start Render
浏览器开始渲染的时间,从用户角度看就是页面上看到第一个内容的时间。
First Interactive
最早的页面可交互时间,比如单击一个链接、单击一个按钮等。
Speed Index
通过微积分定义的,用于衡量网页性能体验的参数。
8.1.5 WebPagetest实际使用中需要解决的问题
WebPagetest API Wrapper,解决与CI/CD流水线的集成。
WebPagetest的私有化部署,解决被测网站部署在公司内部的网络中,处于外网的WebPagetest无法访问的问题。
8.2 后端性能测试主流商业工具LoadRunner
8.2.1 LoadRunner的基本原理
后端性能测试工具首先通过虚拟用户脚本生成器生成基于协议的上虚拟用户脚本,然后根据性能测试场景设计的要求,通过压力控制器控制、协调各个压力产生器以并发的方式执行虚拟用户脚本,并且在测试执行过程中,通过系统监控器收集各种性能指标以及系统资源占用率,最后通过测试结果分析器展示测试结果。
LoaderRunner中,Virtual User Generator对应的就是虚拟用户脚本生成器,Controller对应的就是压力控制器和系统监控器,Load Generator对应的就是压力产生器,Analysis对应的就是测试结果分析器。
8.2.2 LoadRunner的主要模块
Virtual User Generator
用于生成模拟用户行为的测试脚本。
Controller
相当于性能测试的控制管理中心,负责控制Load Generator产生测试负载,以执行预先设定好的性能测试场景同时,它还负责收集各类监控数据。
Analysis
强大的分析插件。
8.2.3 基于LoadRunner的性能测试实战
收集性能需求
录制并创建虚拟用户脚本
验证脚本的正确性
执行性能测试
分析测试报告
系统性能调优
8.3 后端性能测试主流开源工具JMeter
8.3.1 JMeter简介
JMeter是一款纯Java应用,是Apache组织的开源项目,是功能和性能测试工具。
8.3.2 JMeter的主要概念
测试计划、线程组、监听器、逻辑控制器、断言(Assert)、配置元件、前置处理器、后置处理器、定时器。
8.3.3 JMeter的使用
被测对象
新建JMeter线程组
创建一个HTTP请求
添加HTTP Header Manager
添加View Results Tree
运行测试查看结果
添加Response Assertion和Assert Results
添加User Defined Variables
添加关联
并发测试
8.4 企业级实际性能测试案例与经验
8.4.1 性能基准测试
Performance Benchmark Test,是每次对外发布产品版本前必须要完成的测试类型。
8.4.2 稳定性测试
可靠性测试,主要通过长时间(7*24h)模拟被测系统的测试负载。
采用“波浪式”的测试负载。
8.4.3 并发测试
在高并发情况下验证单一业务功能的正确性以及性能的测试手段。
“集合点”概念。
8.4.4 容量规划测试
为了完成容量规划而设计的测试。
容量规划的目的是,当系统负载将要达到极限处理能力时,解决我们应该如何通过垂直扩展(增加单机的硬件资源)和水平扩展(增加集群中的机器数量)增加系统整体的负载处理能力的问题。
8.5 大型互联网产品的全链路压测
8.5.1 全链路压测的定义
全链路压测是基于真实的生产环境来模拟海量的并发用户请求和数据,对整个业务链进行压力测试,试图找到所有潜在性能瓶颈并持续优化的实践。
8.5.2 单系统的独立压测
对生产环境中的单击或者单系统进行独立的压测。
8.5.3 海量并发请求的发起
8.5.4 全链路压测流量和数据的隔离
首次全链路压测的准备周期会需要半年以上的时间,其中最大的工作量在于对现有业务系统和中间件的改造,来实现压测流量和数据的隔离。
在对各个业务模块和中间件添加特殊标记的改造过程中,更倾向于通过中间件来尽可能多地完成特殊数据标记的处理和传递。
8.5.5 实际业务负载的模拟
采用已有的历史负载作为基准数据,然后在此基础上进行适当调整。
8.5.6 真实交易和支付的撤销以及数据清理
对交易的流量和数据进行了特定标记。
第九章 准备测试数据
9.1 准备测试数据的基本方法
9.1.1 基于GUI操作生产测试数据
手工操作或UI自动化生成。
创建测试数据最原始的方法。
9.1.2 通过API调用生成测试数据
目前主流的测试数据准备方法。
9.1.3 通过数据库操作生成测试数据
目前主流的测试数据生成方法。
9.1.4 综合运用API和数据库生成测试数据
实际的测试实践中,很少使用单一的方法生成测试数据,基本上都采用API和数据库相结合的方式。
最典型的应用场景是,先通过API调用生成基础的测试数据,然后使用数据库的CRUD操作生成符合特殊测试需求的数据。
9.2 创建测试数据的方法
9.2.1 实时创建方法
在测试用例的代码中实时创建要使用到的测试数据。
弊端
实时创建测试数据比较耗时。30%-40%的时间花在了测试数据的实时准备上。
测试数据本身存在复杂的关联性。
来自于微服务架构的挑战。并不是所有的服务都是可用的,这就给准备测试数据带来了新的挑战。
9.2.2 事先创建方法
在准备测试环境时预先将测试需要用到的数据全部准备好,而不是在测试用例中实时创建。
“最致命”的问题是出现“脏”数据。数据在使用前被修改导致。
9.2.3 综合运用实时创建方法和事先创建方法
“死水数据”,那些相对稳定、不会在使用过程中改变状态并且可以多次使用的数据。
“活水数据”,那些只能使用一次或者经常会修改的测试数据。
9.3 测试数据的“银弹”——统一测试数据平台
9.3.1 测试数据准备的1.0时代
将测试数据准备的相关操作封装成数据准备函数。
9.3.2 测试数据准备的2.0时代
测试数据生成器模式
生成器模式是一种数据准备函数的封装方式。在这种方式下,当你需要准备测试数据时,不管情况多么复杂,都可以通过简单的一行代码调用来完成。
UserBuilder.build();UserBuilder.withCountry("US").build();User.Builder.withCountry("US").withPaymentMethod("Paypal").build()
测试数据的生成策略
SEARCH_ONLY:只从被测系统的已有数据中搜索符合条件的数据。
CREATE_ONLY:测试数据必须是新建的。
SMART:不关心测试数据是新建的,还是通过搜索得到的,只希望以尽可能短的时间得到需要的测试数据。
OUT_OF_BOX:测试数据一定是开箱即用的数据。spring boot基于spring的基础上对大量配置进行了默认设置,使你在使用时拿来就可以用,不需要进行大量的配置设置
9.3.3 测试数据准备的3.0时代
测试准备函数“跨平台能力”。
统一提供各类测试数据的Restful API服务,称为“统一测试数据平台”
把很多的细节隐藏起来,对外提供统一的测试数据准备的接口,以方便各类测试框架的灵活使用。
9.3.4 测试数据准备的4.0时代
引入测试数据准备函数的脚手架代码。各个业务团队的开发人员只要基于我们提供的脚手架代码,来完成测试数据函数的具体实现。脚手架代码可以按预先定义的方式打包成JAR包,并且这些JAR包将以动态注册的方式加入到统一测试数据平台中。整个过程可以通过统一测试数据平台的界面来完成,并且整个过程完全不需要重启统一测试数据服务。这里的关键词是“去中心化”和“平台化”。
9.3.5 大数据技术在测试数据准备中的应用
采用大数据平台对线上数据的离线统计分析结果来动态调整默念值,这样构造的数据就会和实际生产环境的数据更加接近。
第十章 自动化测试基础架构的建设与实践
10.1 从小作坊到工厂:Selenium Grid简介
10.1.1 测试基础架构的基本概念
执行测试的过程中用到的所有基础硬件以及相关的软件。
10.1.2 早期测试执行环境的问题
测试执行机器与测试用例的关系是不透明的,即每个测试用例都需要人为设置测试执行机器。为了改善这种局面,Selenium Grid应运而生。
不同浏览器的兼容性测试。
同一浏览器的不同版本的兼容性测试。
机器名或IP发生变化,以及需要新增或减少测试机器。
GUI自动化测试用例的数量比较多的情况。
10.1.3 Selenium Grid简介
一种可以并发执行GUI测试用例的测试执行机器的集群环境,采用的是Hub和Node模式。
Selenium Hub用来管理各个Selenium Node的注册信息和状态信息,接受远程客户端代码的测试调用请求,并把请求命令转发给符合要求的Selenium Node来执行。
10.1.4 传统Selenium Grid的搭建方法
本地运行JAR包,Hub和Node使用的命令行参数不同。
10.1.5 基于Docker的Selenium Grid的搭建方法
通过Docker File配置启动。
10.2 从小工到专家:测试执行环境架构设计基础
10.2.1 测试执行环境概述
狭义的测试执行环境,仅指测试执行的机器或者集群。
广义的测试执行环境,除了包含具体执行测试的测试执行机器人以外,还包括测试执行的机器或者集群的创建与维护、测试执行集群的容量规划、测试发起的控制、测试用例的组织以及测试用例的版本控制等。
广义的测试执行环境也称为测试基础架构。
测试架构投入意义
简化测试执行过程。
最大化测试执行机器的资源利用率。
提供大量测试用例的并发执行能力。
提供测试用例的版本控制机制。
提供友好的用户界面。
提供与CI/CD流水线的统一集成机制。
高效测试基础架构考虑方面
测试基础架构的使用者无须知道测试基础架构的内部设计细节,只要知道如何使用就行。
对于维护者而言,测试基础架构具有“易维护性”。
测试执行集群的规模可以随着测试用例的数量自动扩容或者收缩。
随着移动App的普及,测试基础架构中的测试执行机器需要支持移动终端和模拟器的测试执行。
10.2.2 测试基础架构的设计
10.2.3 早期的测试基础架构
10.2.4 经典的测试基础架构
10.3 从小工到专家:测试执行环境架构设计进阶
10.4 实战案例:大型全球化电商网站的测试基础架构
10.4.1 统一测试执行服务
10.4.2 统一测试数据服务
10.4.3 测试执行环境准备服务
10.4.4 被测系统部署服务
10.4.5 测试报告服务
10.4.6 全局测试配置服务
10.4.7 大型全球化电商网站测试基础架构的使用示例
CI/CD流水线脚本会以异步或者同步的方式调用被测系统部署服务,安装、部署被测软件的正确版本。
被测系统部署完成后,CI/CD脚本就会调用统一测试执行服务。统一测试执行服务首先会根据之前部署的被测软件版本选择对应的测试用例版本,然后从代码仓库中下载测试用例的JAR包。接下来,统一测试执行服务会交付测试用例的数量、浏览器的要求,以及需要完成执行的时间作为参数,调用测试执行环境准备服务。
测试执行环境准备服务首先会根据传过来的参数,动态计算所需的Node类型和数量,然后根据计算结果动态加载更多基于Docker的Selenium Node到测试执行集群中。此时,动态Node加载是基于轻量级的Docker技术实现的,所以Node的启动与挂载速度都非常快。于是,统一测试执行服务通常以同步方式调用测试执行环境准备服务。
测试执行环境准备好之后,统一测试执行服务就会通过Jenkins Job发起测试执行。测试用例在执行过程中会依赖统一测试数据服务来准备测试需要用到的数据,并通过全局测试配置服务获取测试相关的配置与参数。同时,在测试执行结束后,还会自动将测试报告以及测试报告的元数据发送给测试报告进行统一管理。
第十一章 软件测试新技术
6个测试主题
探索性测试
测试驱动开发 Test Driven Development, TDD
精准测试
渗透测试
基于模型的测试
人工智能在测试中的应用
11.1 发挥人的潜能——探索式测试
11.1.1 软件测试与招聘面试的类比
面试前了解候选人简历
根据简历情况和岗位要求,设计高质量的面试题
面试中回答符合预期,就结束话题
面试中回答不符合预期,顺着回答,进行针对性的提问(探索性测试)
11.1.2 探索式测试的定义
具有即兴发挥、快速实验、随时调整等特征。
三个关键概念
探索式测试是一种软件测试风格,而不是一种具体的软件测试技术。
探索式测试强调独立测试工程师的个人自由和责任,其目的是持续优化其工作的价值。
在执行探索式测试时,在整个项目中,建议将测试学习、测试设计、测试执行和测试分析作为相互支持的活动,并行执行。
11.1.3 探索式测试与即兴测试(Ad-hoc Testing)的区别与联系
11.1.4 探索性测试的开展
采用分层测试策略。
首先对软件的单一功能进行比较细致的探索式测试。“探索”的过程主要是基于功能需求以及非功能性需求进行扩展和延伸,期间可以采用类似“头脑风暴”的工具(XMind)帮助我们整理思路。
基于你的怀疑,进一步设计新的测试用例来验证你的猜测。
接下来,开展系统交互的探索式测试。采用基于反馈的探索式测试方法。
11.2 测试先行——TDD(Test Drive Develop, 测试驱动开发)
11.2.1 TDD的核心理念
TDD并不是一门技术,而是一种开发理念。
TDD的核心思想是在开发人员实现功能代码前,先设计好测试用例、编写测试代码,然后针对新增的测试代码编写产品的功能代码,最终目的是让新增的测试代码能够通过。
11.2.2 TDD的优势
保证开发的功能一定是符合实际需求的。
更加灵活的迭代方式。
在TDD的流程里,需求是以测试用例描述的,非常具体。可以边开发边测试,不需要等到产品交给测试人员后,再整体测试。
保证系统的可扩展性
为满足测试先行的灵活迭代方式,开发人员会设计更松耦合的系统,以保证系统的可扩展性和易修改性。
更好的质量保证。
TDD要求测试先于开发。在每次新增功能时,都需要先用测试用例去验证功能是否正常,并运行所有的测试来保证整个系统的质量。
测试用例即文档
在TDD过程中编写的测试用例,首先一定是符合用户实际需求的,然后一定是符合系统的业务逻辑的,所以可以直接根据测试用例生成需求文档。
11.2.3 TDD的实施过程
为需要实现的新功能添加一批测试。
运行所有测试,看看新添加的测试是否失败
编写实现软件新功能的代码
再次运行所有的测试,看是否有测试失败。
重构代码
重复以上步骤直到所有测试通过。
11.2.4 TDD进阶
首先,需要控制TDD测试用例的粒度。
其次,要保持代码的简洁和高效。
最后,通过重构保证最终交付代码的优雅和简洁。
11.3 打蛇打七寸——精准测试
所谓精准测试,就是借助一定的技术手段,通过辅助算法对传统软件测试过程进行可视化、分析以及优化的过程。
精准测试的核心,借助一些高效的算法和工具,收集、可视化并且分析原生的测试数据,建立起一套测试分析系统。
11.3.1 传统软件测试的主要短板
测试的维护成本日益升高。
测试过程低效
“杀虫剂”效应。测试用例越来越多,而产品的“免疫力”也越来越强。早期已经发现了80%的缺陷,当前用例无法发现其它20%缺陷。
缺乏有效的回归用例选取机制
即使只修改一行代码,也需要做全回归测试。
测试结果可信度不高
测试数据的统计分析过程中的大量人工因素导致测试数据本身的技术公信力不够高。
需要依靠管理手段来保证真实的测试数据被准确的记录。
无论是白盒测试技术还是黑盒测试技术都有其局限性
这些测试方法都依赖于产品代码,一旦代码发生改变,很多测试都会失效,因此很难适应高速迭代的开发流程。
目前的代码级测试和代码覆盖率技术还不支持测试用例级别的覆盖率分析,导致用白盒测试无法区分代码覆盖率的提升是因为哪个测试用例。
11.3.2 精准测试的核心思想
精准测试是对传统测试的补充。
精准测试采用的是用黑盒测试与白盒测试相结合的模式。
精准测试的数据可信度高。
数据都是由系统自动录入和管理的,人工无法直接修改数据。
精准测试的过程不直接面对产品代码。
通过算法和软件实现测试数据与过程的采集,因此不直接面向代码,也就不会严重依赖于产品代码。
精准测试是与平台无关的、多维度的测试分析算法系统。
精准测试是一种通用的测试分析系统,独立于任何测试平台,其内部算法和业务无关,因此适用于各种不同的产品。
11.3.3 精准测试的具体方法
业界最成熟并且已经产品化的精准测试体系来自国内的“星云测试”。可参考其官网的《星云精准测试白皮书》
四项核心技术
软件精准测试示波器
测试用例和被测产品代码的双向追溯
智能回归测试用例选取算法
测试用例聚类分析
11.4 安全第一——渗透测试
11.4.1 渗透测试的定义
由专业安全人员模拟黑客,从系统可能存在漏洞的位置进行攻击测试,在真正的黑客入侵前,找到隐藏的安全漏洞,从而达到保护系统安全的目的。
11.4.2 渗透测试的常用方法
针对性的测试
这种测试方法也叫做“开灯”测试。因为针对性的测试是在测试人员完全了解系统内部情况的前提下开展的,区别于外部人员完全不知道系统内部细节而进行的渗透测试。
由公司内部员工和专业渗透测试团队共同完成。
外部测试
针对外部可见的服务器和设备(域名服务器、Web服务器、防火墙、电子邮箱服务器等),模拟外部攻击者对其进行攻击,以及如果成功入侵了,会入侵到系统的哪一部分,又会泄露多少资料。
内部测试
由测试工程师模拟内部人员在内网(防火墙内)进行攻击。
盲测
在严格限制提供给测试执行人员或团队的信息的前提下,由他们来模拟真实攻击者的行为。
双盲测试
也叫“隐秘测试”。在这类测试中,不但测试人员对系统内部知之甚少,而且被测系统内部也只有极少数人知道正在进行安全测试。
11.4.3 执行渗透测试的步骤
规划和侦查
安全扫描
静态分析(主流工具有Fortify SCA和Checkmarx Suite)和动态分析
获取访问权限
维持访问权限
入侵分析
11.4.4 渗透测试的常用工具
Nmap:进行主机检测和网络扫描的重要工具。
Aircrack-ng:评估Wi-Fi网络安全性的一整套工具。
sqlmap:一种基于命令行的开源渗透测试工具。
Wifiphisher:一种恶意接入点工具,可以对Wi-Fi网络进行自动钓鱼功能。
AppScan:IBM公司的一款企业级商业Web应用安全测试工具,采用的是黑盒测试,可以扫描常见的Web应用安全漏洞。
11.4.5 渗透测试的收益
通过渗透测试,公司可以识别出主要漏洞,并决定修补漏洞的优先级,同时合理分配系统补丁安装的时间,以确保系统环境的安全性。
避免了安全漏洞,也就是避免了不必要的损失。
11.5 用机器设计测试用例——基于模型的测试
MBT是自动化测试的一个分支。它是将测试用例的设计依托于被测系统的模型,并基于该模型自动生成测试用例的技术。其中,被测系统的模型表示被测系统预期的行为,也代表我们对被测系统的预期。
11.5.1 MBT的基本原理(Model Based Testing)
MBT的基本原理是通过建立被测系统的设计模型,并结合不同的算法和策略来遍历该模型,从而生成测试用例。
11.5.2 常用模型简介
有限状态机
状态图
UML(United Modeling Language,统一建模语言)
11.5.3 常用MBT工具
BPM-X
fMBT
GraphWalker
11.5.4 MBT的优势
测试用例的维护更轻松
可以尽早发现软件缺陷
测试自动化的水平更高
测试覆盖率变得更高,使得彻底测试(穷尽测试)成了可能。
基于模型间接维护测试用例的方式更高效。
11.5.5 MBT的劣势
学习成本较高。
使用MBT的初期投资较大
早期根据模型生成测试用例的技术并不非常成熟。
11.6 人工智能在测试领域的应用
11.6.1 人工智能概述
人工智能分为弱人工智能和强人工智能,前者只关注于完成某个特定的任务,如AlphaGo,而强人工智能目前还只存在于科幻电影中。
弱人工智能已经在很多领域取得突破,主要归功于一种用于实现人工智能的机器学习技术。
机器学习的关键点是利用机器学习算法来训练模型,利用大量的样本数据进行训练,获得最优模型,用于对未来的问题进行预测与解决。
人工神经网络
遗传算法
11.6.2 人工智能在软件测试领域的应用
应用TensorFlow通过软件界面截图寻找Bug。
利用K近邻算法协助失败测试用例的分析
利用模式识别算法来模糊定位GUI的元素
利用路径权重来自动生成测试用例
11.6.3 基于人工智能的测试工具
Appvance IQ
Applitool
MABL
Test.AI
Airtest
第十二章 测试人员的互联网架构核心知识
12.1 测试工程师掌握大型网站架构知识的必要性
12.1.1 基于消息队列的分布式系统测试设计
12.1.2 缓存的示例
12.1.3 架构知识的学习方法
12.2 大型网站架构介绍
12.2.1 最简单的网站架构
12.2.2 应用和数据分离的网站架构
12.2.3 引入本地缓存和分布式缓存的网站架构
12.2.4 引入应用服务器集群的网站架构
12.2.5 引入主从分离的数据库
12.2.6 引入CDN服务器和反向代理服务器的网站架构
12.2.7 引入分布式文件系统和分布式数据库系统的网站架构
12.2.8 基于业务拆分和消息队列的网站架构
12.2.9 基于分布式服务的网站架构
12.2.10 微服务架构
12.2.11 下一代微服务架构——服务网格
12.3 网站高性能架构设计
12.3.1 前端的高性能架构
12.3.2 后端服务器的高性能架构
12.4 网站高可用架构设计
12.4.1 造成网站不可用的主要原因
网站高可用架构设计
12.5 网站可伸缩架构设计
12.5.1 可伸缩性和可扩展性的区别
12.5.2 分层的可伸缩性架构
12.5.3 应用服务器的可伸缩性设计
12.5.4 缓存集群的可伸缩性设计
12.5.5 数据库的可伸缩性设计
12.6 网站可扩展性架构设计
网站可扩展性架构设计的案例
事件驱动架构与消息队列
引入消息队列后的测试关注点