add 15/16/17 (#813)
|
@ -0,0 +1,7 @@
|
|||
# 第十五章 软件测试
|
||||
|
||||
软件测试是质量保障的核心手段,开发和测试很像软件研发的辩证对立统一两个方面,一个实现预期,一个验证预期,仿佛通过“竞争合作”的方式共同打造服务用户的软件产品。本章将聚焦于软件测试的内涵定义、目标、基本概念和应用实践,通过实际的工程问题帮助读者梳理软件测试的脉络,回答以下几个问题:
|
||||
|
||||
* 软件测试是什么?
|
||||
* 测什么,谁来测,怎么测?
|
||||
* 大公司是如何做软件测试的?
|
|
@ -0,0 +1,81 @@
|
|||
## 15.1 木头与软件测试的故事
|
||||
|
||||
转眼之间,木头已来到自己职业生涯的第8个年头,本月初有一位新同事小陈入职,木头带领他一起完成了一次线上bug的排查。借由这次机会,小陈很快地熟悉了项目中的相关feature,定位到了代码中的问题,并在木头的帮助下得出了解决方案:需要改一行代码,然后加两行日志收集的代码方面进行修复情况跟进。
|
||||
|
||||
### 15.1.1 一行代码引起的“惨案”
|
||||
|
||||
拿定主意,新人小陈熟练的打开IDE,写好并提交了代码,就找到木头,兴致勃勃地讲述了想法,打算一气呵成地完成代码签入、热修复(hotfix)、部署和发布,完成自己职业生涯的第一个“代码产品化”里程碑。木头见他热情可嘉,回想起了自己初入职场的青葱岁月,也没有直接泼冷水,打趣说道:
|
||||
|
||||
“好啊,不过你这个里程碑肯定早晚会拿到,你先别急着合入代码修改,先针对这段改动丰富一下单元测试,然后最好自己也多测几轮,这样再上线,比较稳妥。这个feature虽然是新feature,不过生产环境目标用户数量也有好几万了。”
|
||||
|
||||
“这...需要吗?一共就一行代码改动,加了个if判断,都是局部变量,不可能出问题啊。”小陈一脸狐疑的说道。他心想自己以往LeetCode战无不胜,写代码经常是一把过,这次就这么简单的改动的话,完全可以省去测试流程。
|
||||
|
||||
“哦,可是这里还加了日志输出,原来是没有这个调用的。”木头一边看着小陈的改动,一边说道。
|
||||
|
||||
```java
|
||||
private void interceptRedirect(String redirectUrl){
|
||||
...
|
||||
traceLogger.infoWithArgs(String.format("Redirect URL: %s", redirectUrl));
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
```java
|
||||
// 以下是示例infoWithArgs的底层实现,并没有在本次修改中被小陈修改。
|
||||
public class TraceLogger {
|
||||
...
|
||||
public void infoWithArgs(String message, Object... args){
|
||||
...
|
||||
info(String.format(message, args));
|
||||
...
|
||||
}
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
“对对,不过这个能出什么问题吗,日志模块的接口到处都在调用,我这里就是把变量的值打印出来而已。而且这个方法貌似已经有一个单元测试在覆盖了,你看这里。”
|
||||
|
||||
```java
|
||||
public void testInterceptRedirect_NoException(String redirectUrl) {
|
||||
...
|
||||
interceptor.interceptRedirect("https://www.bing.com/search?q=software+testing");
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
聊到此处,木头直觉事情没有那么简单,“你调用日志的时候,没有传入参数,却调用了infoWithArgs,嗯,这样会有问题吗?”。
|
||||
|
||||
“我从上面直接复制粘贴过来的,应该没问题吧?单元测试是通过的。”
|
||||
|
||||
两人一起研究起了一下这段代码,并对现有的单元测试进行了扩展,提供了一些新的数据用例,实战了一下结对编程。没想到,两人很快发现在入参URL为某些特例(包含%a、%b或%c)的时候,字符串格式化语句会出现异常 `MissingFormatArgumentException` 报错,导致整个业务流中断。而这个所谓的特例,在这个业务场景中和代码逻辑中频次很高,可能会导致线上数千用户的体验中断。
|
||||
|
||||
```java
|
||||
@Test
|
||||
public void testInterceptRedirect_NoException(String redirectUrl) {
|
||||
...
|
||||
interceptor.interceptRedirect("https://www.bing.com/search?q=software+testing");
|
||||
// 新增的用例会在原有代码上触发 `MissingFormatArgumentException` 异常
|
||||
interceptor.interceptRedirect("https://www.bing.com/search?q=%e5%be%ae%e8%bd%af%e4%b8%ad%e5%9b%bd");
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
小陈惊出一身冷汗,自己心心念念的职业里程碑,差点演变成大型翻车现场;本来是打算修复一个线上问题,没想到差点制造出新问题。这时的他再看木头,不由觉得木头周身有一圈佛光,是上天派来拯救他的。“看来一行代码改动也要仔细研究,而测试是很好的代码问题的检验手段,需要多下功夫研究研究。”小陈顿了顿,然后激动地说:“软件bug的代价太大,宁可错杀,不可放过。”小陈又燃了起来,不过这次却让木头很是欣慰,听的频频点头。
|
||||
|
||||
“哈哈,你讲的挺逗,确实如此,bug能咱们自己发现修掉,就不要让客户帮咱们体验。从某种程度上来说,编程是对逻辑复杂性的管理。咱们的项目代码行数是百万级别的,逻辑复杂,情境和用例非常多,每一处修改都有可能牵一发而动全身。全面的测试可以帮助我们在更早的阶段评估代码修改的影响。”
|
||||
|
||||
木头接着说:“其实你不用后怕,咱们的代码合入之后,还会经过层层检测。代码合入主分支之后还会经过bvt测试、更全面的集成测试,热修复上线之前还会经过验收测试、回归测试以及压力测试,再部署到测试环境,进行内部的自测。之后都没问题,才可能发布到预生产环境、生产环境。所以你这个问题,大概率能够在上到预生产之前被拦截下来。我估计集成测试都过不了,哈哈。”
|
||||
|
||||
小陈挠头附和打个哈哈,心想,这些你不早说,原来还有这么一大堆测试。
|
||||
|
||||
又聊了几句,两人看时间不早了,就由小陈着手把代码修复完整后提交了,等待其他同事帮忙评审,就先下班了。
|
||||
|
||||
“还有一条规则,周五下午坚决不发版。下周见!”木头大手一挥,消失在大楼转角。
|
||||
|
||||
### 15.1.2 小陈的反思
|
||||
|
||||
今天发生的事情对小陈触动很大,回家后他依然在思考,为什么自己当时写代码时没有想到这个特例(corner case)?木头说的“全面的测试”,又如何理解其具体含义?一方面,他今天只接触了单元测试,而木头还提到了其他很多种类的测试。另一方面,测试团队似乎很重要,可以帮忙发现很多问题,而自己作为开发人员、代码修改的第一作者,和“全面的测试”之间的关系是什么?是否软件质量要依赖于测试团队的工作?
|
||||
|
||||
最终,如果有了“全面的测试”,是不是软件质量就可以高枕无忧了?
|
||||
|
||||
带着这样一个又一个问题,小陈查了查资料,看到一句“测试是为发现错误而执行程序的过程”,还没来得及梳理出脉络,就感觉困意袭来,于是洗漱睡觉,结束了充实的一天。
|
|
@ -0,0 +1,31 @@
|
|||
## 15.2 故事分析-软件测试的复杂性
|
||||
|
||||
软件测试的重要性是和软件所服务的用户数量正相关的:越是成熟的公司,越是大型的软件就越需要完善测试,层层把关。软件测试的复杂性会随着软件本身的复杂性的上升而上升。如果是简单明确的程序或者脚本,自测验证即可;而对于例如微软内部的Windows或者Office大型产品线,测试的计划需要在产品设计阶段就介入,在架构和组件层面要考虑软件的可测试性,确保Testable,并设计和逐步建立完善的、全方位的测试体系,来保障问题尽早被发现(Fail fast)。
|
||||
|
||||
尤其对于微软这样用户规模很大(亿级别)的公司来讲,任何一次“小的”软件质量事故,哪怕是只有万分之一的概率出现,也可能会影响成千上万的用户,破坏体验、口碑,甚至演变成为公关事件,影响公司声誉,造成巨大的商业损失。
|
||||
|
||||
<img src="img/Slide4.SVG"/>
|
||||
|
||||
### 15.2.1 软件测试的目标定位
|
||||
|
||||
既然如此,什么能为软件产品的上线、版本更新带来信心呢?测试这一活动,通过衡量实际情况与预期之间差距,正是增加对软件质量信心的关键活动。团队在上线前,看到一份“测试通过”的测试报告,自然会更放心一点。这是软件测试服务于质量保障的重要结合点。
|
||||
|
||||
<img src="img/Slide5.SVG"/>
|
||||
|
||||
不过,“增强信心”仅仅是软件测试的结果,而绝不是目的。从刚刚木头和小陈的故事当中,我们也可以体会到这点:因为代码有单元测试覆盖,所以会小陈会觉得自己的修改有保障,获得了“迷之自信”;但实际情况是,代码依然存在严重问题。而小陈后来反思的时候,看到了书上的"测试是为发现错误而执行程序的过程",也得到了一些启发。这些共同说明:
|
||||
|
||||
1. 开发人员的自测是有很大局限性的。
|
||||
2. 仅靠测试是无法保障产出高质量软件。
|
||||
3. 从心理学角度上讲,测试不应该是“自卖自夸”;而应该勇于质疑软件质量,“疑罪从有”,努力揭露软件问题。
|
||||
|
||||
### 15.2.2 测试的复杂性来源
|
||||
|
||||
故事中,小陈认为代码的修改量很小,并且是局部变量的改动,“问题不大”,忽视了所谓的“边界”情况。根据实践中的经验,软件开发中出现的问题往往不必和精巧的设计、核心的业务逻辑有必然联系,而更多出现在被疏忽的“边缘”环节上。而测试就是要发现软件错误和异常情况。
|
||||
|
||||
当今时代编程已经发生了更多的演化:我们有越来越多的类库、别人写好的方法可以调用,有越来越多的“轮子”、“巨人的肩膀”来加速功能实现。这就意味着,**一行代码可能暗藏着很深的调用栈和很长的调用链条**。木头作为资深的工程师,意识到即使是小的改动也可能引入问题,尤其是在复杂的软件系统、数据场景中。当软件足够复杂,所谓的“简单”的改动已经非常不可信,务必进行相应的测试,以避免潜在的问题。
|
||||
|
||||
木头作为经验丰富的同事,担任着指导和教育小陈的角色。他强调了测试的重要性,并解释了测试的流程和不同阶段的测试类型。在软件开发中,测试团队在保证软件质量方面的重要作用。然而质量并不是测试团队的“锅”,软件质量保障是整个团队的责任。
|
||||
|
||||
要做好测试,需要了解和运用一系列的测试知识和工具。木头也提到,不仅仅有单元测试,还有其他类型的测试,如集成测试、回归测试、压力测试等,并解释了这些测试环节在保证软件质量方面的作用:在不同层次和环境中验证软件的正确性和稳定性。
|
||||
|
||||
总的来说,软件测试发展至今,体系庞大、功能也很强大,但它不是万能的。它是确保软件质量的最为关键和最被依赖的环节。开发人员应该积极参与测试,并与测试团队合作,打造测试体系,诚实勇敢地去发现问题、重视问题、面对问题、评估问题和最终解决问题。
|
|
@ -0,0 +1,113 @@
|
|||
## 15.3 什么是软件测试
|
||||
|
||||
软件测试似乎并没有所谓的“权威”的定义,说法众多,比较常见的说法是,软件测试是一种实际输出与预期输出之间的验证和比较的过程。测试的意图是验证软件的行为,进而发现会导致系统失败的问题。结合前文,“测试是为发现错误而执行程序的过程”,我们提炼两个关于测试的重点:
|
||||
|
||||
- 测试过程体现了实际输出与预期输出间的比较。
|
||||
- 要带着**质疑**的视角,“疑罪从有”,提供客观、独立的结论,暴露软件实施的风险。
|
||||
|
||||
在时间要求上,测试这个过程可以很简短,内部达成某个或某几个维度指标的验证即可;也可以持续到所有利益相关者都满意为止。
|
||||
|
||||
### 15.3.1 以问题为导向
|
||||
|
||||
问题是测试的最重要的产出之一,谈及测试我们先全面的认识一下软件的“问题”。我们一般习惯称软件的问题为“Bug”,不同语境下也可以用为“Defect缺陷”、“Exception异常”、“Fault错误”和“Issue问题”等代指,他们分别强调了问题的不同方面或者不同部分。以下是一些由表及里的概念:
|
||||
|
||||
| 概念 | 解读 |
|
||||
| ------------------- | -------------------------------------------------- |
|
||||
| Symptom 症状 | 问题的表征,如崩溃、严重的卡顿 |
|
||||
| Issue 问题 | 一般是问题的表象的描述,代表了用户对这个问题的感知 |
|
||||
| Defect 缺陷 | 可能指逻辑上的疏漏、不足之处和软件设计层面的问题 |
|
||||
| Exception 异常 | 强调“和预期不符”,不一定是真的问题 |
|
||||
| Fault/Error 错误 | 问题在程序层面的表现,如段错误 Segment Fault |
|
||||
| Root Cause 根本原因 | 错误的根源,即导致代码错误的根本问题 |
|
||||
|
||||
从问题表象到根本原因之间的距离可长可短,一个程序的崩溃、请求的失败,一般首先反映在用户体验上;开发团队可以将问题定位到一段出错的代码中;然而一段代码的错误或异常,可能是由其他代码导致的,比如Out of memory内存溢出(OOM)问题,往往报错的代码只是压倒骆驼的最后一根稻草,问题的根本原因可能隐藏在整体的软件内存管理、资源利用效率和方式上。再发散一点,一个软件问题的根本原因,可能和软件的工程流程、发布流程、团队管理甚至企业文化都有些许联系。
|
||||
|
||||
微软内部的产品组会在临近上线前组织“Bug-bash”(打虫子)大会,召集开发团队的所有人,产品、开发、测试,全都来对产品进行“Self-host”自用自测,发现问题就报告出来。这样做有很多好处,一方面,鼓励大家多多用自己开发的软件,增强主人翁精神;另一方面,团队发现问题和解决问题的人坐在一个屋子里、或者处在一个会议中,缩短问题解决的周期,效率很高。
|
||||
|
||||
一般用于描述一个问题的报告称为“Bug report”(缺陷报告)。它通常由以下几个主要部分组成,以帮助开发团队定位和修复问题:
|
||||
|
||||
1. 标题:
|
||||
Bug Report的标题应简明扼要地概括问题,使读者能够快速了解报告的主要内容。
|
||||
|
||||
2. 描述(Description):
|
||||
描述部分详细说明了bug的情况,包括以下内容:
|
||||
- 测试环境和准备工作:描述进行测试时所用的软件环境、硬件设备、配置等信息,以及为了测试而进行的准备工作。
|
||||
- 测试步骤:清晰列出每一步所执行的操作和动作,包括输入的数据、点击的按钮、导航的路径等。
|
||||
- 实际发生的结果:记录在执行测试步骤后实际观察到的结果,可能包括错误信息、异常行为、崩溃等现象。
|
||||
- 应该发生的结果:根据规范和用户的期望,描述在特定情况下应该发生的预期结果。
|
||||
3. 附加材料:
|
||||
如果有必要,Bug Report可以附带其他补充材料,例如相关联的bug编号、输出文件、日志文件、调用堆栈的列表、截屏等。这些附件或链接有助于进一步的问题分析和复现。
|
||||
4. 其他字段:
|
||||
在Bug Report中还可以包含其他字段,用于提供更多信息,如严重程度(Severity)、功能区域等。这些字段有助于对问题进行分类、评估和优先级排序。
|
||||
|
||||
<img src="img/Slide6.SVG"/>
|
||||
|
||||
Bug Report是一个重要的工具,它能够帮助测试团队和开发团队之间进行有效的沟通和合作,以及保障软件质量的提升。编写清晰、准确的Bug Report有助于减少问题的误解和漏洞,提高问题解决的效率和质量。
|
||||
|
||||
<img src="img/Slide7.SVG"/>
|
||||
|
||||
那么,测试是通过怎样的过程和方式把问题挖掘出来的呢?
|
||||
|
||||
### 15.3.2 测试的分类:测什么和怎么测
|
||||
|
||||
软件测试的被测对象被称为Software Under Test(SUT)。根据具体的测试目的和对被测对象的关注点的不同(在测试什么内容就叫什么测试),测试可以分为如下几类:
|
||||
|
||||
1) 功能验证
|
||||
|
||||
- **功能测试**(Function test):测试软件系统的设计功能是否符合规格要求。
|
||||
- **结构测试**(Structure test):白盒测试中对模块内部结构进行测试,验证代码的逻辑正确性和覆盖率。
|
||||
- **冒烟测试** (Smoke test):冒烟测试的目的是验证软件的核心功能是否正常,以便快速发现关键问题和确保软件稳定性。它主要关注于系统的基本功能和主要路径(Golden Path),而不是详尽地测试每个细节和功能。
|
||||
- **可用性测试**(Usability test):从使用的合理性和方便性等角度进行测试,发现人为因素或使用上的问题。
|
||||
- **配置测试**(Configuration test):测试软硬件系统平台对软件的支持和兼容性。
|
||||
- **构建验证测试**(Build Verification Test):也被称为构建验证或基本验证测试。它被用于验证软件构建(build)的基本稳定性和可用性,简称BVT。
|
||||
- **回归测试**(Regression Test):对一个新的版本,重新运行以往的测试用例,看看新版本和已知的版本相比是否有“退化”(regression)。
|
||||
|
||||
2) 性能验证
|
||||
|
||||
- **性能测试**(Performance test):验证系统是否满足规格中规定的性能要求,如响应时间、吞吐量、处理精度、缓冲区大小、内存占用等。
|
||||
- **负载测试**(Load test):用满负荷长时间测试系统的稳定性(此时性能可以忽略)。
|
||||
- **压力测试**(Stress test):验证系统在超负荷和异常环境下的运行能力和稳定性(此时性能可以忽略)。
|
||||
- **可靠性测试**(Reliability test):评估系统的平均失效时间(MTBF)和故障停机时间(MTTR)。
|
||||
|
||||
3) 辅助测试
|
||||
|
||||
- **兼容性测试**(Compatibility test):测试不同版本间的兼容性,尤其关注文件存储/读取的兼容性,包括向下兼容和交叉兼容。
|
||||
- **安全测试**(Security test):验证系统的安全性,确保系统对于潜在攻击的防护措施有效。
|
||||
- **可访问性测试**(Accessibility test):验证系统对于聋哑人、盲人等特殊用户的易用性和无障碍访问性。
|
||||
- **本地化/国际化测试**(Localization test):主要验证软件在不同地区和语言环境下的本地化和国际化适配性,特别关注界面文字的正确性。
|
||||
|
||||
<img src="img/Slide8.SVG"/>
|
||||
|
||||
这些测试分类方式有助于测试团队根据不同的测试目标和需求,制定合适的测试策略和执行计划。此外,测试可以按照如下几个方面进行分类:
|
||||
|
||||
#### 1. 按照测试设计的方法分类
|
||||
|
||||
- **黑盒测试**:通过观察系统的输入和输出,以及对系统功能的期望行为进行测试,不需要了解系统内部的实现细节。黑盒测试在设计的过程中,把软件系统当作一个“黑箱”,无法了解或使用系统的内部结构及知识。也可以说是“Behavioral Test Design”,从软件的行为,而不是内部结构出发来设计测试。
|
||||
- **白盒测试**:基于对系统内部结构和代码的理解,设计测试用例来验证系统的逻辑正确性和代码覆盖率。在设计测试的过程中,设计者可以“看到”软件系统的内部结构。“白盒”并不是一个精确的说法,因为把盒子涂成白色,同样也看不见箱子里的东西;叫玻璃盒测试又有点奇怪。
|
||||
- **灰盒测试**:结合黑盒测试和白盒测试的特点,既关注功能验证,又考虑系统内部的结构和实现。灰盒和白盒有同样的问题,其实这里的灰可以理解为“半透明”或者灰色地带的“灰”,表示可以一定程度的看清内部情况的“毛玻璃盒”;或者黑盒上挖了一个小洞,可以“偷窥”到内部的一部分。
|
||||
|
||||
<img src="img/Slide9.SVG"/>
|
||||
|
||||
黑盒测试更接近用户视角,可以作为整体系统测试的一部分,验证系统在各种使用情况下的功能和行为。白盒测试对测试人员的要求更高,有时需要侵入系统、进行访问和修改,但更接近代码层面,可以发现潜在的逻辑错误、边界条件问题和代码覆盖不足的情况。“灰盒测试”还不是一个很流行的说法,但是在实战中其实比较常见,比如结合逆向工程的测试,或者测试期间可以通过常规或非常规的手段,观察到运行时软件内存堆栈里的数值存储情况;这可能对测试人员的综合能力要求更高。下文讲到的穿透测试和这个概念很相关。
|
||||
|
||||
#### 2. 按照测试的实施方法分类
|
||||
|
||||
- **自动测试**:利用自动化工具和脚本执行测试,提高测试效率和一致性,适用于重复性较高的测试任务。
|
||||
- **手动测试**:通过人工操作和观察进行测试,适用于需要人的主观判断和复杂交互的测试场景。
|
||||
- **探索测试**(Ad hoc Test or Exploratory Test):探索性测试是一种以探索为导向的测试方法,通过同时进行测试设计和执行,测试人员可以自由地、发散地探索软件系统,发现新的测试场景、缺陷和问题。这也是一种很有技术含量的测试技术,微软还专门出过一本书就叫“探索式软件测试”。
|
||||
- **穿透测试**(Penetration Testing),也简称为Pen Test或漏洞测试,是一种安全评估方法,旨在模拟真实攻击者的行为,以发现和验证计算机系统、应用程序或网络中的安全漏洞和弱点。
|
||||
|
||||
测试并不一定要全部依赖于自动化测试,也不一定自动化越多越好;手动测试在某些情况下仍然具有必要性和重要性:例如,探索性测试(Exploratory test)这种兼具灵活性和创造性的测试方法在自动化测试中难以实现;手动测试能够模拟真实用户的操作和交互,更好地评估系统的用户体验;在某些情况下,系统的变动频繁或测试需求经常变化,手动测试具有更高的灵活性和适应性,能够快速调整测试策略和执行方式。
|
||||
|
||||
#### 3. 按照测试的范围分类
|
||||
|
||||
- **单元测试**:对软件的最小单元(如函数、方法)进行测试,验证其独立性和功能正确性。
|
||||
- **集成测试**:测试不同模块之间的接口和交互,确保模块能够协同工作。
|
||||
- **系统测试**:以整个系统为被测对象进行测试,验证系统在各方面的功能和性能。
|
||||
- **验收测试**:由最终用户或客户进行的测试,以确认软件是否满足其需求和期望。
|
||||
|
||||
<img src="img/Slide10.SVG"/>
|
||||
|
||||
单元测试确保代码的正确性,集成测试验证模块间的协作,系统测试验证整个系统的功能和性能,而验收测试确认软件是否满足用户需求和准备进行部署,他们依次越来越接近用户视角,也依次越来越“黑盒”、远离代码。这些测试阶段一起构成了软件开发周期中的重要质量保证措施。
|
||||
|
||||
有时单元测试与集成测试的边界并不是很明确,我们可以这样理解:理想情况下,在单元测试中,被测试的单元应该与代码中的其他部分完全隔离。这种“纯粹”的单元测试方法意味着,被测试的单元在其自身边界之外访问的所有内容都需要用模拟对象或代理对象替代。然而,这种方法的缺点在于,模拟对象需要被维护,以确保其行为与实际实现同步。因此,单元测试通常也以被测试的单元可以访问其他单元的方式实施。如果测试明确针对不同单元之间的交互,那么它们就不再是单元测试,而是集成测试。实际上,集成测试通常也会使用与测试驱动程序相同的框架,并使用模拟对象来替代尚未实现或对测试无关的组件。
|
|
@ -0,0 +1,125 @@
|
|||
## 15.4 软件测试的设计和实施
|
||||
|
||||
前面的章节介绍了测试是什么和为什么测试,接下来我们将进一步探讨测试体系是如何设计和实施的。设计是软件开发中非常重要的一个环节,我们前面第六步中已经探讨过软件各个层次的设计:架构设计、概要设计和详细设计。而软件测试的设计,着眼于如何把软件中各个层面的问题找出来,并在开发的阶段中尽早地暴露问题。因此,在软件设计的阶段就应该引入软件测试的方案的设计探讨。测试方案的设计可以涵盖如下几个层次:
|
||||
|
||||
### 15.4.1 软件系统的可测试性
|
||||
|
||||
可测试性是指软件可以被完全有效测试的程度。在开发设计和实现的过程中,通常可以采用如下的思路来提高软件系统的可测试性:
|
||||
1. 选择更加模块化和解耦的设计,引入设计模式。
|
||||
2. 简化测试环境的搭建流程。
|
||||
3. 启用依赖注入。
|
||||
4. 选择简明且易封装的算法。
|
||||
5. 定义清晰且易于测试的接口。
|
||||
6. 使用测试“钩子(hook)”(仅仅为了测试方便而写的额外的功能)。
|
||||
|
||||
这些手段很多需要在架构设计、组件设计阶段就开始考量。因此,一个最简单和普遍的提高可测试性办法,就是让开发或测试人员在需求或设计评审中发出“灵魂拷问”,“我们怎么来测试这个东西?”,将开发可被测试软件的这个想法植入团队的大脑中。近年来随着软件测试在技术广度上的发展,我们有了越来越多的开源工具和平台可以依赖,似乎没有什么是真正不可测的了。测试数据可以批量生成,软件电量消耗可以精确抓取;微软的手机和电脑协同连接软件Phone Link,测试过程中需要装有软件的手机和电脑进行同步协同操作,二维码扫码配对,也都通过软件模拟或硬件支持的手段解决了,不仅可测,而且可以自动化地测。
|
||||
|
||||
更进一步,可测试性不仅关乎测试本身和软件架构,更关乎从用户和商业角度出发的软件设计合理性,“如果一个功能都没办法测试(或很难测),这个功能真的有必要存在吗?”这个时候我们不妨问问,这个功能的边界、给用户带来的价值、触发条件、衡量成功与否的标准都定义清楚了吗?这些要点都关乎测试的**预期**,或者说“Expected Outcome”。因此,我们在产品设计阶段引入测试的讨论,对于产品的成功也有很大意义。
|
||||
|
||||
### 15.4.2 整体的开发驱动模式
|
||||
|
||||
软件的开发首先应该是由外部的用户需求或商业需求主导的,所以高水平的测试人员需要理解软件功能的商业价值、设计的合理性,在测试的过程中帮助改善软件的设计。软件功能和需求的设计,和测试中要验证的“输出满足预期”,本质上是同源的,都是为了增加软件的质量、商业价值服务的。测试团队和产品团队本质上对于软件功能、质量有着相同的要求。换言之,当整个团队在需求理解和质量要求上高度协同一致的时候,测试也可以驱动开发。
|
||||
|
||||
测试驱动开发(Test-Driven Development),简称TDD,是一种软件开发方法(Development Approach),它要求在编写实际代码之前先编写测试用例。开发人员通过先编写测试用例,然后编写足够的代码以满足测试的需求。TDD实际在操作上逻辑很简单,也是比较“符合直觉”的一种开发方式,基本上就是在写测试、写代码、运行测试和重构代码之间不断迭代,直到将程序的功能实现完整。在编码的过程中,可能会用到“两顶帽子”类似的思维,编码时切换思考角度,在“测试功能”、“实现功能”和“重构代码”三种思考模式之间不断切换,笔者觉得这非常有趣。
|
||||
|
||||
<img src="img/Slide11.SVG"/>
|
||||
|
||||
测试驱动开发有助于实现更高的代码质量,鼓励开发人员编写更模块化、可扩展和可维护的代码,形成更好的代码设计,提高代码的可读性、可维护性和可重用性,同时,TDD通过提供全面的测试覆盖和及时的反馈,增强了团队对于产品的自信心;此外,测试用例作为明确的需求规范,充当“可以运行的程序文档”,也促进了团队成员之间的沟通和理解。可谓好处多多。
|
||||
|
||||
然而,是否要在团队里采用或推广这种开发方法,是一个实践层面的复杂问题。文化层面上,TDD要求团队成员具备测试和质量意识,重视产品架构和和维护性,测试、开发、产品团队之间有较好的协同和紧密合作;产品层面上,需要产品需求和功能定义清晰,变动不宜过于频繁。因此,TDD更适合具备一定规模的团队和长期稳定的项目。所以,对于时间压力大、探索和创新型的项目以及更注重灵活快速的团队,不能将TDD生搬硬套;也没有必要强推一个成型团队转型TDD。这也许是国内互联网公司较少看到TDD实践的原因之一。当然,这也和技术领导人的风格和企业文化主导思想有很大关系。
|
||||
|
||||
在微软,工程师文化盛行,所以有不少团队实打实的在用TDD,笔者有幸和Microsoft Form产品研发经理聊天,对方谈到TDD带来的好处和大家的热情,眼睛里闪烁着兴奋光彩。在和一位阿里巴巴做保险业务开发的朋友聊天,了解到,因为产品涉及到支付、定损、保险精算和“真金白银”,对整体代码测试覆盖率要求很高(98%以上,关键模块要求100%),测试团队和开发团队都要求会写代码、写测试、懂业务,与其被动的追赶覆盖率,不如直接采用测试驱动,边测边写。
|
||||
|
||||
总之,测试驱动开发是一种经典的开发方法,不必强求,不妨一试。和测试驱动开发并列的开发驱动模式还包括行为驱动开发(Behavior-Driven Development,BDD)和验收测试驱动开发(Acceptance Test-Driven Development,ATDD)等;其中ATDD将测试更加后置在交付用户之前(或发布之前),其重点是验收测试用例的设计,这里限于篇幅不再过多赘述。重要的问题是,在软件开发的实践中,我们打算把测试放在什么地位(重要性)和环节(时间点)上,这个问题的答案会很大程度上决定软件的质量情况和测试工具、开发系统的采用。
|
||||
|
||||
### 15.4.3 测试的需求和目标
|
||||
|
||||
很少有人会问,为什么要做软件测试,这件事似乎在专业的软件团队里是与生俱来就要做的事情;但经常能听到团队的测试人员抱怨,“我们的产品研发团队根本就不重视测试”,“测试的地位低”等等声音。笔者认为这些“牢骚”其实往往是测试人员的妄自菲薄或者“有恨无人省”的委屈怨言。
|
||||
|
||||
测试的出发点应该从商业角度和用户角度的现实需求出发,求真务实,暴露问题,让软件质量的真相浮出水面。比如,一个软件产品要在中国上线,那要符合遵循《中华人民共和国个人信息保护法》(PIPL),而一个软件系统内部的数据流处理是否违背了个保法的原则,需要通过测试验证手段,结合网络数据流监测或抓包工具,像探针一样插入“黑盒”内进行测量才能知晓。在美国,医疗仪器设备软件产品要遵循FDA美国食品药品监督管理局所指定的要求标准,FDA对其下注册的软件产品的软件测试流程有非常严苛的要求,会派审核人员去软件开发团队对测试流程进行督导和盘查,确保软件实现了声称的规范水准。
|
||||
|
||||
以上提及的例子是典型的从实际出发的软件测试需求,有着明确的目的和外部需求。“符合预期”可以是非常宽泛的,提升软件的CMMI成熟度也可以是测试的一个出发点。在上一小节我们也提及了从目的出发的测试的分类方法,可用性、可靠性到安全性、合规性,可能会出现问题的角度都可以形成相应的测试需求,对应到相应的测试方法。
|
||||
|
||||
### 15.4.4 测试技术方案选型
|
||||
|
||||
“Test Pass”,测试通过,是软件开发的一个重要的反馈信号或里程碑,好的测试工具、系统或技术方案应该具备较高的稳定性,环境部署方便,运行过程和结果清晰简明等特点,在保证测试结果有效性的基础上,其应该能够帮助研发团队更快、更高效地达到Test Pass,从而将产品开发推动到下一个阶段。此外,在选择测试工具和技术方案时,还可以考虑以下因素:
|
||||
|
||||
- 技术栈和平台:测试方案一般首先依赖于项目所使用的技术栈和平台。单元测试方面,Java主流框架有`Junit`、`TestNG`、`Mockito`等,C#有`MSTest`、`xUnit`、`nUnit`等;Web UI测试可以用`Playwright`、`Selenium`;移动端跨平台方案`Appium`;云测试系统`Hydra Lab`;Android端用`Espresso`,iOS app使用`XCTest`。
|
||||
- 测试需求和目标:测试的需求和目标对于测试方案的制定有很大的决定作用,确定要测试的功能、性能、安全性等方面的要求,以及所需的测试覆盖范围和深度。比如,安全性要求高的系统需要设计穿透测试,运用逆向工程、模拟黑客攻击来测试系统的“防御力”,而受众小、处于孵化器的项目则没有必要将问题复杂化。
|
||||
- 团队技能和经验:优先根据团队成员的技能和经验,选定大家相对比较熟悉的测试工具和技术,确保能够有效地应用和支持所选方案。
|
||||
- 开发环境和工作流程:选择与现有环境和工作流程相协调的工具和技术,以便实现无缝的集成和自动化。微软Azure DevOps平台有很高的灵活性,支持多种主流平台、测试工具的集成。
|
||||
- 可用资源和成本效益:评估可用的资源和预算,对照考虑工具和技术的成本效益,来确定是否有足够的资源来支持和维护所选的测试工具和技术,以及它们是否能够提供预期的价值和回报。
|
||||
- 社区支持和生态系统:还可以综合考虑测试工具和技术的社区支持和生态系统,优先选择受欢迎、活跃的工具和技术,以便能够获得广泛的支持、文档和资源,并从社区的经验和最佳实践中受益。
|
||||
|
||||
开发团队可以综合考虑以上因素,结合项目的具体情况和需求,选择适合的测试工具和技术方案,来实现高效、可靠的测试和质量保证。
|
||||
|
||||
### 15.4.5 开发和测试团队的分工和流程
|
||||
|
||||
在传统的瀑布模式下,开发团队在完成开发后将软件交付给测试团队进行测试。开发团队负责设计、编码和集成,而测试团队负责执行测试用例、发现和报告缺陷。在这种模式下,开发和测试是连续的但分离的阶段。敏捷开发模式秉承“小步快跑”的理念,强调开发团队和测试团队之间的协作和整合。开发团队和测试团队一起参与每个迭代周期,共同制定需求、设计、编码、测试和验证,鼓励开发和测试团队在整个开发过程中密切合作。
|
||||
|
||||
一般而言,开发团队的需要负责:
|
||||
|
||||
- 设计和实现软件的架构、功能和特性。
|
||||
- 编写高质量的代码,并进行单元测试。
|
||||
- 解决开发过程中的技术问题和挑战。
|
||||
- 提供必要的技术文档和支持。
|
||||
|
||||
而测试团队的责任包括:
|
||||
|
||||
- 制定测试策略、计划和测试用例。
|
||||
- 执行各种测试(如单元测试、集成测试、系统测试、验收测试等)。
|
||||
- 发现、报告和跟踪缺陷。
|
||||
- 分析测试结果,提供质量评估和建议。
|
||||
|
||||
随着敏捷方法的兴起,开发团队和测试团队之间的责任划分越来越模糊。其实根据上面的职责界定,也可以看出各项职责之间都有着几乎高度重合或者密不可分的联系,比如,设计软件功能和设计测试用例实质都是在描述对软件的预期;执行测试虽然是测试团队的主要工作,开发自己写代码难道不需要自测吗?有的经验丰富的开发就是通过灵活运用TDD或者测试工具、代码检测工具,实现功能的阶段就把测试的活都干了,代码Pull request里面还附上了简明的“测试报告”(一般叫How this is tested 或者 How I test it),导致测试阶段完全挑不出毛病来;虽然一般约定是开发负责写单元测试,而测试人员也可以帮忙改进或创建单元测试,来提升覆盖、发现缺陷。
|
||||
|
||||
会写代码的测试在国内叫“测试开发工程师”,薪资比一般的测试人员要高很多,这类职位在阿里巴巴、京东这样的大厂招聘页面上很常见;国外叫“Software Development Engineer in Test”,简称SDET,或者“Quality Assurance Engineer”,简称QAE。测试开发在越来越多的“入侵”软件工程师的地盘,也许,随着AI和大语言模型技术LLM辅助编程的崛起,个体能效的提升,开发和测试之间的边界会越来越模糊,最终融合在一起。
|
||||
|
||||
总而言之,软件产品的开发和测试是紧密联系的,是对同一个问题的两个不同关注侧面;开发工程师和测试工程师作为重要部分共同构成了软件产品团队,共同为产品的成败负责。如果简单的把开发看成“实现功能的”,把测试看成“保证没bug的”,认为只有测试为质量负责,那么开发就有可能在写代码上放飞自我;认为开发应该为所有线上bug背锅,那么测试就会变得形式化,走马观花,形同虚设。
|
||||
|
||||
另外,从时间这个维度或者测试流程设计上看,测试和开发团队之间如何避免“互相等”的情况,也和权责、合作模式、开发流程密切关联。低效的情况无非就是测试人员无版本可测,或者开发人员写完代码但却发现没人能马上测试,或者迟迟没有测试bug产出或报告结果,导致发版延迟。这种情况一般需要贯彻敏捷开发“小步快跑”的理念,将功能拆解,让代码实现和测试用例设计可以并行,开发和测试可以“错峰”和衔接;同时也需要管理者洞察这种“空窗期”,通过整个产品团队范围进行人员资源的优化调配来解决。
|
||||
|
||||
最后,文化上,开发团队和测试团队之间的合作应该是紧密的,彼此互相支持、协作和沟通,团队领导需要建立良性文化,出了问题要一起反省,剖析改进,避免陷入相互甩锅的无效争执;成功优质的上线也要对整个产品团队的所有贡献者一同感谢。要相向而行,实现共同的目标:交付高质量的软件,让用户满意。
|
||||
|
||||
### 15.4.6 测试用例的设计
|
||||
|
||||
测试用例(Test Case)之于测试工程师,犹如程序代码之于开发人员。测试用例是测试工作产出的最重要的“工件”之一。一个软件测试用例可以包含以下核心元素:
|
||||
|
||||
- 用例名称(Name):用例的唯一标识符或名称,清楚地描述了被测试功能或场景。
|
||||
- 测试目的(Objective):明确说明了测试用例的目标和意图,即要测试的具体方面或功能。
|
||||
- 预设条件/前提条件(Preconditions):列出执行测试用例之前必须满足的条件或环境设置。
|
||||
- 测试数据(Test Data):指定用于执行测试的输入数据,包括必要的参数、配置和初始状态。
|
||||
- 测试步骤(Test Steps):详细描述了按照哪些顺序和方法执行测试用例,包括操作和预期结果。
|
||||
- 预期结果(Expected Results):明确说明每个测试步骤的预期输出或期望结果。
|
||||
- 优先级(Priority):指定测试用例的优先级,以帮助测试人员在测试计划中确定执行顺序。
|
||||
|
||||
测试用例设计方法和技巧是软件测试中非常重要的一部分。当我们把软件的内部逻辑看做为一个“黑盒”的时候,可以采用以下方法和技巧来设计测试用例:
|
||||
|
||||
1. 场景法(Use Case Testing):根据用户使用软件的场景来设计测试用例,例如登录、注册、搜索等。这种从用户使用场景视角出发的用例设计其实是比较符合直觉和常用的设计方法。
|
||||
2. 等价类划分法(Equivalence Partitioning):将输入值划分为有效和无效的等价类,从每个等价类中选择一个或多个测试数据作为测试用例。通过将输入值划分为有效和无效的等价类,可以减少测试用例的数量,提高测试效率。
|
||||
3. 边界值分析法(Boundary Value Analysis):测试输入数据的边界值,包括最小值、最大值、中间值等。这种方法是对等价类划分的补充。
|
||||
4. 错误推测法(Error Guessing):凭经验,列举出程序中所有可能有的错误和容易发生错误的特殊情况,设计相应的测试用例。
|
||||
5. 因果图分析(Decision Table Testing):通过绘制因果图来梳理一个程序中的输入输出组合,明确测试预期结果和前置条件,进而设计测试用例。
|
||||
6. 功能图分析(State Transition Testing or Functional Graph Analysis):通过绘制功能图、系统状态迁移图来帮助测试人员理清软件系统的功能结构、状态变化,并基于功能图进行测试用例的设计和分析。功能图一般由状态迁移图和逻辑功能模型组成。一系列状态及其依赖的输入/输出数据满足的“条件对”组成测试用例。
|
||||
|
||||
<img src="img/Slide12.SVG"/>
|
||||
|
||||
这里限于篇幅,我们不再对每一个用例设计方法展开叙述。笔者认为,这些设计方法的核心价值在于从不同的角度为用例设计提供了思路,而其最终目的是服务于测试覆盖的完善、质量控制,最终落脚到用户价值。比如,我们从用户场景出发可以创建出登录、下单、结账等各类测试基本用例,通过因果分析来明确预期输入输出,通过等价类分析来丰富用例内容,进而再通过错误推断和边界分析来全面覆盖逻辑角落(corner case),这些方法可以非常好地组合起来帮助完善测试。但是,一定要明确,我们的最终目标产出不是因果图,不是等效类,而是经过有效用例验证后的高质量软件产品。此外,很多时候,我们从产品设计和需求文档层面出发,就可以明确很多输入输出预期,其中可能就暗含了因果图,功能图的逻辑体系。测试和开发人员在借助这些分析工具之前,全面的学习产品设计和需求文档可能比仅凭分析的纸上谈兵,有更大的意义。
|
||||
|
||||
从测试用例的组织方式上看,单个用例的范围可大可小,但一般会聚焦在一个功能点上,同一个模块的多个功能点所对应的用例,可以组合成为一个测试用例集(Test Suite),往往可以覆盖到一个场景(scenario)或者服务于一个特定的目的(如冒烟测试用例集)。在Azure DevOps系统中,提供了各层次的测试对象的定义,Test Plan可以包含Test Suite和Test Case,代表了一次具体的测试执行计划。这些测试对象可以在Azure DevOps上方便的进行管理、关联和重用,从而提高测试效率。
|
||||
|
||||
<img src="img/Slide13.SVG"/>
|
||||
|
||||
### 15.4.7 谁来测:测试人员的职业素养
|
||||
|
||||
DevOps和敏捷开发理念的崛起和流行,让测试人员和开发人员之间的权责边界变得模糊,软件产品出了质量问题,越来越多的是整个团队为之负责,而不是简单地让测试人员“背锅”。这种模糊和融合也意味着对测试人员的要求更加综合。谁来测,或者说,测试人员的水平和心态,都可以对测试执行成果产生很大的影响。软件测试团队的角色和责任包括设计可用性测试的测试场景,分析测试结果并向开发团队提交报告,创建测试设计、流程、用例和测试产品文档,并按照设定的标准和流程进行测试。在笔者看来,测试人员应该具备:
|
||||
|
||||
1. 软件行业的商业意识。
|
||||
2. 和用户换位思考的同理心。
|
||||
3. 对于新技术的学习能力。
|
||||
4. 对产品设计的基本理解。
|
||||
5. 扎实的计算机和编程功底。
|
||||
|
||||
如果想走技术路线,测试人员可以深入学习软件开发知识,熟悉更多的测试工具,增加自己测试“探针”触及的深度,掌握自动测试、效能测试、穿透测试等。同时,也可以通过对产品和业务的理解,逐步拓宽自己的视野、提升思维,为产品交互逻辑发现和解决问题,创造价值;甚至逐步发展“老板思维”,展现自己的商业逻辑上的见解,成为测试管理者,为公司优化流程,实现利润最大化。
|
||||
|
||||
总之,测试人员不要妄自菲薄,假设“测试不受重视”,出于一些外界的成见给自己的能力和成长设限,从而错失发展良机。软件质量关乎着软件的成败和生命线,从质量出发,或者从团队能效、自动化出发,测试工作都大有可为。
|
|
@ -0,0 +1,118 @@
|
|||
## 15.5 软件测试在微软
|
||||
|
||||
微软是毫无疑问的软件行业巨头,在全球有超过18万员工,很多产品线活跃用户数都是亿级别或者十亿级别,因此微软非常重视软件测试和软件质量保障,其在测试领域的实战和发展历程也十分有参考意义和代表意义。
|
||||
|
||||
### 15.5.1 发展历程
|
||||
|
||||
如果想了解微软是如何进行软件测试的,有一本书《微软的软件测试之道》(How We Test Software at Microsoft)是我们通过搜索引擎很容易定位到的。这是一本由前微软公司的测试专家Alan Page、Ken Johnston等于2008年合著、2009年翻译在国内出版的一本软件测试方面书籍。该书探讨了微软在软件测试领域的实践经验和方法,并分享了他们在微软测试团队所采用的测试策略和技术。《微软的软件测试之道》是一本重要的软件测试指南,对于想要了解和改进软件测试实践的人员来说具有很高的参考价值。然而这本书毕竟距现在“年代久远”,软件行业发展迅速,微软也在2010年后历经组织变革和业务战略调整。
|
||||
|
||||
实际上,微软曾经设立过SDET(Software Development Engineer in Test)这一职位,专门负责撰写测试代码、驱动工程自动化和建立质量控制系统,但在2015至2018年期间微软进行了多次组织架构和角色调整,逐步将SDET测试开发职位与SDE开发职位进行合并,逐步取消了SDET这一个头衔。
|
||||
|
||||
因此,为了促进更紧密的跨职能的团队合作,如今的微软已不再设立专门的SDET职位,而是将大部分测试工作融入到开发工程师的角色中。曾经在2008年,微软测试和开发人员的占比几乎是1:1;而今天,“纯粹”的测试工作一般由外包人力承担。专职测试人员在人数上相对于开发的少了很多(小于10%),主要负责手工测试、增量验证、探索测试等测试内容的执行,在微软内部仍然扮演着重要角色。
|
||||
|
||||
这当然不意味着微软不重视测试和质量方面的工作,《微软的软件测试之道》一书的作者也在这些变革发生后,表达了自己的看法:这一变革突出了对于用户需求和团队成员技能多样性的重视,通过融合提升团队敏捷性,让软件工程师的技能更全面,从而更灵活、更能适应变化。微软依然保留了Software Quality Engineering这一专业化分工(人员占比小,同时Quality也比Testing的责任范围更大:"Software Quality Engineering",软件质量工程,是一个更广泛的领域,它涵盖了软件开发和测试过程中的质量保证、质量控制和质量改进等方面),负责确保软件的质量和稳定性。
|
||||
|
||||
<img src="img/Slide14.SVG"/>
|
||||
|
||||
这种“逆分工”的变化趋势并非微软独有,Google和Facebook也在同一时期完成了类似的转变。这一变化,一方面明确了开发团队应该同时负责和推动自动化测试的搭建,提高效率,并为质量负责;另一方面,也反映了软件开发流程和商业模式的演化。早期互联网基础设施并不发达的时候,软件通过软盘、光盘等实体介质分发销售、拷贝,所以软件分发、更新的灵活性都比较差,软件如果无法在分布前充分测试导致遗漏严重的Bug、漏洞一起刻入发行版光盘中,可能会造成非常难以处理的线上事故,造成“覆水难收”的困局,直接攸关软件的成败和生死。所以软件交付需要极高的计划性和严格的质量把控,投入大量软件测试。
|
||||
|
||||
然而,随着互联网的迅速发展,以下几点变化,是这一融合的重要背景:
|
||||
1. 软件分发基础设施的完善:软件产品、各类应用通过网络分发、“打补丁”的成本在逐步降低,且发布平台、分发渠道也变得越发完善。
|
||||
2. 用户数据收集渠道的完善:收集线上用户反馈和诊断数据的渠道越来越通畅和多元:期初可能以邮件沟通为主,用户使用软件遇到问题就通过邮件联系开发团队;后来,各种应用内问题反馈,第三方的反馈平台、诊断数据平台、灰度测试平台、实验控制平台,使得软件团队可以“分包”一部分测试给愿意承担更大风险、提前尝鲜的内测(Alpha/Beta)用户,更早地以更小的代价发现软件问题并着手修复。
|
||||
3. DevOps持续集成系统的完善:CI/CD系统(例如微软的Azure DevOps)可以很容易地将各种类型的自动化测试嵌入到软件研发流程中,成为整个工作流的一部分自动触发。
|
||||
|
||||
总之,这种趋势和整个软件工程基础设施的升级密不可分,同时也蕴含了对软件工程人才综合能力的更高要求。软件工程师团队需要应用各种手段、更强大的工程能力高效地交付高质量的产品。通过将测试技能融入开发过程中,微软希望工程师团队能够综合参与和统筹需求分析、流程架构设计和编码,更好地理解软件系统和功能,进而更好地设计测试和质量保障方案。此外,这种整合也寄希望于加强开发团队对自己开发的软件产品质量的责任感,加强团队协作。
|
||||
|
||||
> 咬文嚼字的讲,“程序员”的主要活动应该是写产品代码,“测试人员”则负责执行测试任务,所有参与软件交付的人员都是“开发人员”。然而在一个敏捷团队中,每一个成员都应关注于交付具有业务价值的高质量产品。软件开发工程师SDE应该跳出框架去思考,着眼于整个产品和产品的生产流水线。
|
||||
|
||||
### 15.5.2 微软的测试实践
|
||||
|
||||
在上文中提到的团队整合的大背景下,微软内部的软件测试实践在各个产品团队的工程师(Software Development Engineer,SDE)们的主导下,呈现出百花齐放的态势:不同产品研发团队各自有自己的测试实践方案。因此很难说微软目前在测试上有一套统一标准的流程,或者说有具体的最佳实践。处于不同成熟度阶段的产品、或不同的技术栈、前端或后端、不同的商业模式(2B或2C),采取的测试策略、模式和目标都不尽相同。不过,微软各个团队在工程师主导、敏捷开发、持续集成等理念上具备共识基础,也最大程度上在复用同一套基础设施,在软件测试采用了很多共性的策略和方法,以下是一些比较常见的实践。
|
||||
|
||||
#### 1. 持续集成和敏捷测试
|
||||
|
||||
微软绝大部分产品研发团队都在Azure DevOps或GitHub平台上进行开发、验证集成和发布。Azure DevOps(简称ADO)平台内置支持的敏捷开发方法,可以方便地实现持续集成和持续交付流程。这意味着软件的功能和改进会定期地集成到主干代码中,自动在代理机器(Build Agent,通常为连接至平台流水线的物理或虚拟机器)上完成构建,并自动化触发测试流程来进行验证。很多团队还会使用Azure DevOps中的测试计划功能来创建和管理测试计划(Test Plan)、测试套件(Test Suite)和测试用例(Test Case)。Azure Test Plans一般用于组织手动测试的信息和记录执行,定制测试需求、跟踪测试进度和与其他团队分享测试用例;也可用于自动化测试。
|
||||
|
||||
Azure DevOps中的“Pipeline”,构建任务流水线,是CI持续集成和CD持续部署的核心组织单元,可以帮助团队串联开发构建任务,实现测试的集成和自动执行。这点和Jenkins、Travis CI等持续集成系统很相似,不过ADO的功能更丰富、更灵活易用。ADO和GitHub也可以无缝集成,是一个综合性、完整度很高的DevOps开发系统,几乎可以覆盖从软件计划到发版的全流程,广泛地被微软各个团队采用
|
||||
|
||||
在代码提交或者创建Pull Request后,Azure DevOps可以自动触发“Pipeline”运行,我们可以在其中内嵌软件测试任务,自动运行包括单元测试、集成测试和其他自动化测试。有了这样的平台之后,我们可以灵活的选择在各个关键环节插入合适的测试流程,来让代码改动可能引入的不同程度的问题适时暴露,从而时刻“拱卫”软件质量。
|
||||
|
||||
> 这里有几个问题:一般有哪些关键环节?什么叫“合适”的测试流程?如何理解“不同程度的问题”?又何谓“适时”暴露?这是几个层层递进的问题,涉及到软件开发中质量、效率和成本之间的平衡,我们将在下一个章节“高效测试”深入探讨。
|
||||
|
||||
<img src="img/Slide15.SVG"/>
|
||||
|
||||
在一次常规的开发、发版流程中(不考虑存在紧急热修复hotfix、A/B testing、或商务合作内测),自动或手工测试可以介入验证的几个关键的时间点包括:
|
||||
|
||||
1. 开发人员创建Pull request之前进行本地编译和测试验证。
|
||||
2. 创建Pull request之后,代码合入开发代码主干之前。
|
||||
3. 代码合入主干之后,或主干上签入了新的改动之后。
|
||||
4. 在主干分支进行定期测试验证,比如每小时一次或者每天两次。
|
||||
5. 从开发主干签出发版节点之后。
|
||||
6. 发版版本构建完成后,部署到内测环境之前。
|
||||
7. 发版版本部署到内测环境之后,部署到生产环境之前。
|
||||
8. 在生产环境发布之后,进行回归测试和持续监控。
|
||||
|
||||
至于具体如何选择时机,和执行什么程度的测试,可以考虑如下的原则:
|
||||
|
||||
1. 测试覆盖率:较早的测试时间点可以在问题进入主干前发现和解决,但由于频次高、效率成本高,无法覆盖所有功能和路径。较晚的测试时间点频次更低,可以进行更全面的测试,包括集成测试和端到端测试。
|
||||
2. 问题修复成本:较早的测试时间点发现的问题修复成本较低,因为问题可能较小且影响范围有限。较晚的测试时间点发现的问题可能会很难排查、对整个产品计划造成较大的影响,修复成本更高。
|
||||
3. 发布进度和风险:较早的测试时间点可以尽早发现问题并提前解决,有助于确保发布进度。较晚的测试时间点可以降低发布到生产环境中出现问题的风险。
|
||||
4. 团队协作和沟通:早期的测试时间点需要开发人员和测试人员之间更密切的协作和沟通,确保及时修复问题。较晚的测试时间点可能需要更多的测试资源和时间,以进行全面的测试。
|
||||
5. 整体质量控制:结合多个时间点的测试可以提高整体质量控制的效果。早期的测试时间点可以发现和解决明显的问题,较晚的测试时间点可以验证整体系统的稳定性和一致性。
|
||||
|
||||
综合考虑上述因素,微软研发团队里的常见的实践是把他们结合起来:早期的测试时间点(相对高频次)侧重于单元测试、集成测试和代码审查,以尽早发现和解决问题。较晚的测试时间点(相对低频次)侧重于系统测试、端到端测试和用户验收测试,以验证整体系统的质量和功能。这样可以兼顾质量控制的全面性和有效性。
|
||||
|
||||
通过提供全面的功能和集成,Azure DevOps将敏捷测试流程“集约化”,提高了协作效率。它支持手动和自动化测试,团队可以利用Azure DevOps的各项功能来实现软件测试的自动化、跟踪、协作和报告。并帮助高效交付高质量的软件,因而在微软内部广泛采用。
|
||||
|
||||
#### 2. 自动化测试
|
||||
|
||||
微软非常注重自动化测试,由于专职的测试人员比例逐步降低,且多通过外包团队执行(有可能开发团队和外包团队不在同一个国度),反向“倒逼”研发团队充分利用各种测试框架和工具来执行自动化测试来保证产品质量。自动化测试当然好处多多,可以提高测试效率、减少人为错误。如上文提到,微软的开发团队可以使用Azure DevOps中的自动化测试功能来运行和管理自动化测试用例。
|
||||
|
||||
奉行测试金字塔的原则,研发团队实施自动化测试会针对不同层次、不同阶段地执行包括单元测试、集成测试、系统测试和用户界面测试等进行综合验证。Azure DevOps(以下简称ADO)平台的pipeline可以在物理机、虚拟机或基于云测试的代理容器上配置测试环境,执行基于Selenium、Appium、NUnit、MSTest、playwright和Visual Studio Test Professional等各类测试任务。ADO通过插件平台“Visual Studio Marketplace”提供了广泛的第一方和第三方的各类Pipeline任务插件,实现第三方测试工具和服务集成。Pipeline运行的代理Agent也支持灵活的配置、镜像复用,为测试环境创建和管理资源、配置环境参数、部署应用程序和数据库等提供方便。通过ADO的内置的测试环境管理,开发团队可以更好地控制和管理测试环境、配置测试环境变量和测试数据集,以确保一致性和可重复性的测试和其在受控且可重复的环境中进行。
|
||||
|
||||
微软内部基于其在GitHub上的开源方案 Hydra Lab 搭建的内部云测试服务,就实现了物理设备上云,全球共享测试资源。Hydra Lab也提供了ADO插件,在ADO平台上可以方便地为流水线集成测试定义和部署任务,完成和持续集成系统的无缝兼容。除了测试运行本身的自动化之外,利用Azure DevOps平台,微软的开发工程师们还会力争在如下两个测试结束后的环节完成自动化:
|
||||
|
||||
- [测试结果展现和分析自动化]:构建流水线运行测试的自动化测试的结果将在任务结果页呈现,为开发人员提供即时反馈。测试结果、覆盖率、缺陷趋势等关键指标可以通过Azure DevOps的仪表板和报表进行展示和共享。Azure DevOps还提供错误分析、趋势可视化等功能,以深入方便开发团队了解的测试活动。
|
||||
- [缺陷管理和跟踪自动化]:Azure DevOps支持缺陷(Bug)和开发任务(Work Item)管理:当测试结果出现问题的时候,平台可以配置自动创建Bug开来捕获、跟踪测试中反映出的问题。测试人员或开发者可以将其与相关的测试用例和测试结果关联起来,实现缺陷和相关测试之间的追溯。
|
||||
|
||||
关于自动化测试在微软的更多实践,我们将在下一个章节“高效测试”进行更深入的探讨和案例呈现,这里主要想给读者一个概要性的认知,微软一直在依托平台建设和测试基础设施的完善,来努力推进全流程的自动化,并且已经取得显著成效。这也包括引入AI、LLM、图像识别等技术来使自动化测试进一步智能化。自动化测试可能短期无法完全替代手工测试(Manual Test),但未来的软件测试一定是想着更高效、更自动、更智能的方向发展的。
|
||||
|
||||
#### 3. 自测、内测和用户反馈
|
||||
|
||||
当一个公司的工测试人员来越少时,我们可以通过测试“众包”的方法,首先让开发团队、公司员工广泛的参与到软件产品自测活动当中,“公司员工自己应该是自己产品的第一批小白鼠”,其次,建立内部测试用户,Alpha/Beta用户,群助我们试用和测试早期版本,发现问题。内测用户群,通常愿意更早的体验新功能。对风险有更高的接受度。这种方法相当于把内部的手工测试的力转嫁转移给了公司内部员工。内测用户的身上。,只要我们能够建立有效的用户反馈渠道。收集他们在测试体验中的问题,就可以很大程度上提高发现软件缺陷的效率。
|
||||
|
||||
在一个团队的集中于测试的资源变得越来越少的情况下,我们可以先采用内部"众包"的方法来解决测试验证软件质量的问题。这是提高测试效率的另一个思路:找到一群愿意“免费”承担风险、帮忙测试和验证产品新功能的群体。具体而言,这样的群体大概有这么几波人:
|
||||
1. 开发团队本身;
|
||||
2. 公司同事;
|
||||
3. 该软件用户中的“发烧友”,通常也叫Alpha/Beta用户。
|
||||
|
||||
微软内部一般一个完整的产品团队都能达到百人规模,而全公司员工有近20万人。所以对于微软而言,如果妥善经营,第一波和第二波群体是庞大的,而且公司内部同事之间的沟通渠道是非常顺畅的。我们可以建立一定的渠道和技术,提升产品在公司内部的知名度,让开发团队和公司员工们广泛参与到软件产品的自测活动中。从立场上讲,每个产品开发成员都应该成为自己产品的第一批“小白鼠”,此乃“分内之事”;而公司内部的员工资源,则是“近水楼台”,可能也关心和乐意试用公司内部的其他产品,可以进一步帮忙扩大测试的覆盖范围和深度。其次,建立内部测试用户群,包括Alpha/Beta用户,他们将在早期版本中试用和测试软件,并帮助我们发现潜在问题。这些内测用户通常对新功能有更高的兴趣和接受度,他们愿意成为早期采用者并提供反馈。通过建立这样的用户群,我们可以将一部分手工测试的工作转移到公司内部的员工身上,他们将成为测试团队的延伸。
|
||||
|
||||
从本质上讲,专业的黑盒测试、探索性测试都是在通过不同的视角验证产品,这种“视角”本身蕴含着巨大的价值。开发人员对自己开发的产品、功能往往缺失“外部视角”。“众包”测试的妙处在于,通过相对安全的“人海战术”提供了多样化的视角,“多线程”地去探索软件的“逻辑黑盒”,找到和暴露问题。同时,也提升了产品和新功能在开发人员、公司同事、内测用户群范围内的知名度,是一个一举多得的聪明的办法,在微软内部非常常见。笔者在微软经常收到Microsoft Teams、Office等团队发来的内测邀请邮件,发现有趣的产品就试一试,如果正巧发现了问题就跑到Windows Feedback Hub或者内部的Yammer、Teams Channel上吼一声。
|
||||
|
||||
这种方法的关键前提是要建立一定的有效用户反馈渠道。通过收集内测用户在测试过程中的问题、诊断信息和建议,我们可以更快地发现软件缺陷并着手修复。很多国内的互联网企业,在推出新功能之前,向长期维护的Alpha/Beta内测用户QQ群发出测试邀请,并实时在群里沟通问题,只要合规合法,这种沟通渠道能带来意想不到的收益,确保了新功能的稳定性和用户满意度。
|
||||
|
||||
当然,为了确保这种"众包"的有效性和高效性,还有一些技巧和注意事项需要考虑:
|
||||
|
||||
1. 提供清晰的测试指导:特别是针对开发团队自测的情况,有的时候测试需要一定的环境配置,为了确保测试参与者能够执行准确和一致的测试,明确定义被测试的软件产品功能、目标和范围,包括确定要测试的功能、预期的测试结果和所需的测试资源,提供清晰的测试指导可以帮助团队在真实的环境中进行测试。测试指导也可以包括如一定的测试用例、测试步骤和相应的预期结果等。
|
||||
2. 注重用户体验和反馈:测试"众包"不仅仅是为了发现软件缺陷,也是为了提供更好的用户体验。因此,鼓励测试参与者从用户角度出发,关注软件的易用性、界面设计和功能完整性等方面。虚心收集用户各方面的反馈和建议,并视情况采纳为改进软件的重要依据,让反馈掷地有声,也是增进社区和自测团队的积极性的好办法。
|
||||
3. 建立沟通和反馈渠道:建立一个开放和透明的沟通渠道,使测试参与者可以随时提问、报告问题或分享意见。这可以通过电子邮件、聊天工具、在线论坛或定期会议等方式实现。
|
||||
4. 激励参与和奖励机制:为了鼓励测试参与者积极参与测试活动,可以考虑设立一定的激励和奖励机制。例如,给予发现bug最多的同学“捉虫达人”的称号,并提供一定的礼品测试参与者奖励或奖金,或在公司内部设立测试竞赛和排名等。这将提高测试参与者的积极性和参与度。
|
||||
|
||||
在微软,测试内部“众包”活动一般被叫做"Bug Bash",在很多产品团队广泛采用。通过充分利用公司内部的资源和智慧,建立提供清晰的测试指导、大家实时沟通交流,激励参与和奖励测试参与者,加强了大家对内部产品的了解和团队间的联系,有的时候还会有“吐槽大会”的效果,十分有趣也很有意义。当然,测试"众包"并不能取代专业测试团队,而是一种补充和增强的方式。专业测试人员负责既定测试策略的制定执行、高级测试技术的应用和质量控制的监督。通过合理结合专业测试和内部众包测试,可以实现更全面、高效和质量的软件测试。
|
||||
|
||||
#### 4. 安全、无障碍和合规测试
|
||||
|
||||
微软作为一家体量巨大、服务众多个人和企业主体用户的软件服务提供商,保护用户隐私、数据安全,重视产品体验的无障碍,既是企业文化和道德的体现,也是商业责任的一部分,并在这些领域投入了大量的资源和实践。
|
||||
|
||||
1) 无障碍测试
|
||||
|
||||
为了让微软的软件产品和服务对于所有人群都更易用,微软遵循了 W3C (万维网联盟) 制定的 WCAG (网络内容无障碍指南),在全公司内提供了无障碍测试的基础设施、工具和流程机制,来确保产品在视觉、听觉和运动方面都能提供良好的用户体验。微软开发了 Accessibility Insights、Accessibility Developer Tools、Accessibility Testing Services等工具,内部还会建立评价体系,鼓励各个产品达到金牌标准。笔者的团队产品每次在评比中获得无障碍金牌评级,都要为此小小的庆贺了一番。
|
||||
|
||||
2) 合规测试
|
||||
|
||||
微软软件开发中的合规(Compliance)一般包括安全和数据隐私保护两个方面,首先要确保软件产品和服务符合各国家地区适用的数据隐私、儿童保护等相关法律、法规和行业标准,比如 GDPR (通用数据保护条例)、PIPL等。可以说,很多法律条款的要求,也是对产品需求的直接要求,可以转化为测试用例。比如PIPL要求“用户给予数据授权之前,应用程序不应有任何网络通信行为”,就提供里比较明确的软件行为预期,形成测试用例。安全方面,微软使用了一套名为 SDL (Security Development Lifecycle) 的流程,并提供了内置在ADO持续集成系统的工具(如静态代码分析、构建依赖扫描)和资源(如安全培训课程体系),将软件安全的要求和检验渗透到软件开发的各个阶段:需求分析、设计、实现、验证、发布和响应(监控),从而确保每个阶段都有相应的安全活动和最佳实践。从软件测试的角度看,微软很多团队都会实施渗透测试、漏洞分析、网络扫描服务、安全审计等:有的团队是内部通过自动化测试完成,有的则聘请外部的专业公司完成。
|
||||
|
||||
通过这些实践,微软可以提供更安全、可访问、隐私保护和合规的产品和服务,面向全球用户提供专业的软件产品。
|
||||
|
||||
以上只是微软在软件测试方面的一些常见做法,实际上微软内部不同团队、不同产品有着多样化的确保产品的质量和用户体验的方法。下一章我们将讨论如何“高效测试”,将有机会进行更多探究。
|
|
@ -0,0 +1,21 @@
|
|||
|
||||
### 思考与练习
|
||||
|
||||
1. 测试的角色(Test)需要独立出来么?如果不需要,会存在什么样的问题需要解决?如果需要,独立出来的测试角色怎么才能发挥作用?有些成功的产品团队或软件公司认为独立的测试角色不需要存在,你怎么看?
|
||||
2. 如何避免测试成为“走马观花”式的流程?从事测试工作的团队成员应该具备哪些职业意识和素养?
|
||||
3. 软件测试的分类思路(taxonomy)是怎样的?
|
||||
4. 如何设计有效的测试用例?有哪些思考方法?什么样的用例是好的测试用例?
|
||||
|
||||
### 参考资料
|
||||
|
||||
[1] 《构建之法》,邹欣,人民邮电出版社
|
||||
[2] 《微软的软件测试之道》, Alan Page / Ken Johnston / Bj Rollison著,张奭 / 高博 / 欧琼 / 赵勇译,机械工业出版社
|
||||
[3] 《致命Bug:软件缺陷的灾难与启示》,金钟河/叶蕾蕾,人民邮电出版社
|
||||
[4] 《软件测试之困:测试工程化实践之路》,肖利琼,人民邮电出版社
|
||||
[5] 《软件测试的艺术》,张晓明译,Glenford J. Myers著,机械工业出版社
|
||||
[6] 微软开源智能云测试平台Hydra Lab,GitHub,https://github.com/microsoft/HydraLab
|
||||
[6] 软件测试,Wikipedia,https://en.wikipedia.org/wiki/Software_testing
|
||||
[7] 软件测试基础,Microsoft Learning, https://learn.microsoft.com/en-us/shows/Software-Testing-Fundamentals/
|
||||
[8] 微软合并测试职位的原因,Linkedin,https://www.linkedin.com/pulse/20140806183208-12100070-why-did-microsoft-lay-off-programmatic-testers/
|
||||
|
||||
特别鸣谢林刚、谢定坤、Kevin Huang、Weiwei Shi、方斌、万敏、杨威、李英霞等各位微软首席技术专家和经理在微软测试发展历程上提供的知识分享和内容支持。
|
После Ширина: | Высота: | Размер: 81 KiB |
После Ширина: | Высота: | Размер: 48 KiB |
После Ширина: | Высота: | Размер: 50 KiB |
После Ширина: | Высота: | Размер: 57 KiB |
После Ширина: | Высота: | Размер: 39 KiB |
После Ширина: | Высота: | Размер: 194 KiB |
После Ширина: | Высота: | Размер: 30 KiB |
После Ширина: | Высота: | Размер: 55 KiB |
После Ширина: | Высота: | Размер: 42 KiB |
После Ширина: | Высота: | Размер: 73 KiB |
После Ширина: | Высота: | Размер: 504 KiB |
После Ширина: | Высота: | Размер: 54 KiB |
После Ширина: | Высота: | Размер: 81 KiB |
После Ширина: | Высота: | Размер: 37 KiB |
После Ширина: | Высота: | Размер: 77 KiB |
|
@ -0,0 +1,7 @@
|
|||
# 第十六章 高效测试
|
||||
|
||||
上一个章节我们对软件测试的概念内涵、重要性进行了综合探讨,这一章,我们将继续聊“软件测试”,不过我们将聚焦在“高效”二字上。
|
||||
|
||||
我们谈及“高效”,一方面意味着要“稳、准”,同时也要“快”。将一切流程和测试都自动化驱动这件事,可能表面上可以加速流程,但是也可能引出测试稳定性下降(或者说测试结果可信度降低)的问题,英文叫 “flakiness”。比如,自动化框架和自动化测试用例本身可能出问题,导致用例失败,而这个失败并不反映产品的质量问题。
|
||||
|
||||
所以,如果真的想实现稳准狠的高效测试,应该从产品特性和发展计划出发,将各类测试技术手段有效结合,组织和团队层面相应配合,并搭上人工智能高速发展的列车,建立智能高效可靠的测试工程体系,达成“Test Excellence”。
|
|
@ -0,0 +1,49 @@
|
|||
## 16.1 一场关于自动化测试的大讨论
|
||||
|
||||
最近一次组织调整后,木头所在的团队负责了一款新的产品的开发,叫“Phone Link”和“Link to Windows”,这是一款微软推出的手机和PC协同体验的跨平台应用,方便用户在Windows上可以直接享用手机上的数据和功能,实现跨屏互联。
|
||||
|
||||
### 16.1.1 让测试“自动"起来
|
||||
|
||||
星期一的组织站会上,木头的同事小陈接到“神圣使命”,请他负责给该应用搭建自动化测试系统。小陈犯了老大难,跑到木头的工位前来吐槽。
|
||||
|
||||
“咱们这个软件太特殊了,需要电脑和手机配对后,放一块用,才能用起来。比如要在Windows的Phone Link上打开手机屏幕,先得拿出手机扫码和电脑配对,然后再到电脑上打开手机屏幕。一个测试用例要来回操作,这个要搞成端到端的自动化,可有点麻烦。”小陈眉头紧皱,一边琢磨一边问。
|
||||
|
||||
木头点了点头,表示理解。“的确,咱们这个软件系统,涉及到跨系统跨设备,可测试性上有些挑战。”
|
||||
|
||||
小陈叹了口气,然后继续说:“而且呢,对这种复杂场景进行自动化测试,估计本身就会有很多的麻烦和不稳定的情况,我刚刚写了个python脚本试图去驱动,跑了三次,都是一些脚本和驱动层面的奇奇怪怪的错误。这东西能自动化测试当然好,可以提高效率和质量,眼下没有靠谱的方案,要不咱们还是手工测试吧,更可靠一些。”
|
||||
|
||||
旁边的老张本来一直在敲键盘疯狂输出,这会儿听见聊得有趣,主动加入进来:“凭我十年工程经验观察,你这活不好干。”小陈心想:“这还用你说。”
|
||||
|
||||
“BUT!你首先要明白,自动化测试,Test Automation,就是让测试自动起来,可不只是UI自动化测试。你刚刚讲的端到端测试,其实是在讲UI测试的自动化。领导让你搞的是自动化测试,没限定在UI测试,对吧?”老张讲的兴致勃勃。
|
||||
|
||||
小陈若有所悟,说道:“嗯,张哥说的有道理。我的思路确实应该打开。不过,打开了思路,又有点不知道具体要干什么了...”
|
||||
|
||||
“可能要从现在的产品开发测试的实际情况出发,从需求出发,把当前没有自动化的测试变成自动的,你看看现在大家是怎么跑单元测试的,是不是自动化的,再看看咱们测试团队现在手里有什么手动测试用例;另外有没有聚焦在软件性能上的测试,是否可以自动化,等等。”老张边想边说:“后端有没有API测试,压力测试的用例,没自动的都让它自动运行起来。”
|
||||
|
||||
木头接起话茬,说道:“还别说,老张思路很赞啊,这么脚踏实地一想,还是有很多事情可以做。”
|
||||
|
||||
“好像单元测试已经自动化在跑了,目前单元测试不通过的代码修改是无法合入到主分支的。后端的API测试我还不太熟悉。性能测试可能也要基于一些用户场景吧。感觉还是需要从UI测试的自动化方案上突破。”小陈又把问题拉了回来。
|
||||
|
||||
老张说:“我能理解你的想法,不过还是有很多方案值得一试,不一定一开始就直接搞手机和PC端到端的UI测试。单一端的冒烟测试或者集成测试和一些针对典型安全问题的漏洞扫描测试,都可以探索。”
|
||||
|
||||
木头看到小陈的眉头越皱越紧,心知老张给的选项有点太多了,微微一思忖,说道:“其实端到端的自动化测试,也可以搞,我之前有朋友搞过,跨平台的自动化测试方案也有的,好像叫Appium,听说是封装了统一的接口,可以兼顾浏览器、Windows、iOS、Android的UI测试。”
|
||||
|
||||
小陈的眼神终于闪过一丝光彩:“你说的测试框架叫什么?Appium是么,我去学习一下。”
|
||||
|
||||
木头继续说:“是的。老张说的很有道理,你如果使用这个框架,可能也是从冒烟测试、简单的用户场景开始做起,一步步把自动化体系搭建起来。”
|
||||
|
||||
老张也发表总结陈词:“没错,小陈你一步步来,这个事情不好做,但是大有可为。可能也要考虑考虑,领导让我们做自动化测试,无非是为了提高测试效率,并且通过自动化的手段不断的为产品发现问题,保证一些固定场景的可靠性。所以提升一定高度的讲,你做的事情意义重大啊。此外,这个事情的不好做,还有一个层面。你刚刚提的是技术上、产品上测试的问题。流程上和团队合作上也有挑战,这方面我是过来人,比如,自动化框架搭好了,谁来负责丰富测试用例,谁来负责维护:比方说,后面软件功能改了,自动化用例没有相应调整,导致自动化测试运行出了问题怎么办之类的,都是问题...”
|
||||
|
||||
老张当然是一片好心,热心分享“经验之谈”和“大智慧”,却不可避免的让小陈的头越听越大。
|
||||
|
||||
“到饭点了,咱们去吃饭吧!”木头看出来小陈面露难色,及时转移话题,为这场自动化测试真理问题的大讨论按下了暂停。
|
||||
|
||||
### 16.1.2 挑战背后的机遇
|
||||
|
||||
距离上一次自动化测试大讨论已经有月余,小陈针对于本部门产品“Phone Link”和“Link to Windows”搭建的自动化测试框架已经小有规模,能够定时运行一些基本的冒烟测试、性能测试,检测到问题后能自动发出邮件报告;小陈还运用了创新的技术手段,把手机扫码这一难题攻破了,大家交口称赞。团队里也有成员向小陈寻求自动化测试支持;小陈也把测试结果汇总成邮件报告,分享给团队。一切比最初预想的顺利。不过,老张在最初提到的问题,比如测试可能运行不稳定、团队合作模式的建立,都依然是遗留挑战。感激之余,小陈经常和木头、老张进行饭聊,在团队的自动化推进道路上寻求启发。
|
||||
|
||||
<img src="img/Slide4.SVG"/>
|
||||
|
||||
随着越来越多的实践、尝试和思考,小陈逐渐感觉到,软件测试像是一个围绕软件行为预期、质量情况的命题,客观评判软件“好不好”,而自动化测试是一个双重命题:既要评判软件“行不行”,又要自动评判,要“快”,帮助整个团队提高测试的可行性,提升“人效”,把宝贵的开发人员的精力从重复性的工作中解放出来。自动化测试的核心依然是测试:如果是无效的测试,自动化起来也没有任何意义;不能为了自动化而自动化,如果搭建了一套自动化的流程,结果维护起来的成本还高于手动测试的执行成本,而收益又没有明显差异,那就需要斟酌自动化的必要性。
|
||||
|
||||
“如果计算机能自己理解软件、探索软件、识别问题,从而对软件进行测试就好了,也不用维护自动化的测试用例,一切会容易很多。”一次午餐时,小陈对木头和老张说。
|
|
@ -0,0 +1,36 @@
|
|||
## 16.2 从手动到自动
|
||||
|
||||
上一章的内容已经触及到了很多关于测试效率的话题,软件测试是一个包含众多子类型和实践的领域,这其中不乏重复性的工作。比如每次发版前执行的回归测试、每次修改代码后运行的单元测试和冒烟测试等等。这些既定的、有明确的的输入和预期输出定义的测试,可以比较方便地进行自动化。在瀑布流开发时代,当开发和测试周期转化相对低频,测试更趋向于在相对长的周期内“一次性”的时候,将测试自动化起来并不是一个十分重要、核心的议题。当敏捷开发、极限编程等强调快速迭代、频繁交付和及时反馈的开发理念和实践流行起来后,测试的频次明显提高,软件复杂度也加速提升,重复的执行一些测试变得“反人性”,从效率和方法上,也都“很low”。
|
||||
|
||||
> PractiTest提供的软件测试年度报告中在过去的一年中有51%的手工测试被自动化测试所替代,但是自动化测试依然无法被当做解决测试问题的“银弹”。
|
||||
|
||||
### 16.2.1 狭义自动化与广义自动化
|
||||
|
||||
简言之,自动化测试就是把测试自动“跑”起来,是利用软件工具和脚本来执行测试任务和验证软件系统的过程,它是持续集成和持续交付(CI和CD, Continuous Integration 和 Continuous Delivery)的核心概念和重要构成。有的关于自动化测试的著述中,将“自动化测试”和“测试自动化”两个概念进行了区分,认为自动化测试仅仅指“测试用例运行”的自动化,而“测试自动化”指测试全流程的自动化,包括对测试的环境准备(Setup)、执行(Execution)、结果分析(Analysis)、报告(Report)、环境清理(Cleanup)和其他辅助流程(Help)的全面(SEARCH全流程)自动化。这有点像“Automated testing”和“Test automation”之间的区别,区分出了“狭义”和“广义”。本书不再进行这样的区分,自动化测试即“Test automation”,指广义的软件测试全流程自动化,这就让我们可以探讨的内涵更加丰富;而且,全流程的自动化也是高效软件开发、时代发展的要求。
|
||||
|
||||
<img src="img/Slide5.SVG"/>
|
||||
|
||||
因此,自动化测试不再是软件测试的一个单一分类,而是一个发展方向,一个对测试的全面“加成”、“赋能”,而且是从深度和广度两个方面上:从深度上,按照上一章的测试分类中的所有测试都可以自动化;从广度上,测试的从测试环境准备、测试数据生成到结果分析的全流程也都可以自动化:
|
||||
- 不同的“端”:移动端Android和iOS、桌面端Windows和Mac OS、浏览器、服务端等等。
|
||||
- 不同的测试类型:UI测试、性能测试、可用性测试、无障碍测试等等。
|
||||
- 不同的流程和环节:测试环境配置、测试数据生成、测试结果分析、测试报告、结果可视化等等。
|
||||
- 测试平台化:测试任务调度、测试设备管理、测试稳定性提升。
|
||||
|
||||
> 上一小节的故事中,“Phone Link”和“Link to Windows”项目的单元测试(白盒测试)已经是自动化的状态了,而更偏向于黑盒测试的UI测试、端到端测试,还没有自动化跑通;而且该测试涉及到多个平台:Windows和Android,还涉及到物理设备(Android手机)扫二维码问题的解决;而小陈将框架搭建起来后,将测试失败后自动发出错误报告给团队的功能也做了出来,这就覆盖了测试报告的自动化;不要小瞧这个自动报告的功能,这个功能对于开发团队非常有用,是串联整个自动化和持续集成的关键的“最后一公里”,而且可以大大提升小陈工作的可见度(visibility)和影响力(impact),可谓一举多得。
|
||||
|
||||
笔者相信,软件自动化测试领域是大有可为的。当下,这个领域的成熟的框架和工具已经非常多,但还没有一个框架、解决方案或平台能通吃这个领域,更多的是在某一个子命题下深耕。同时,从深度上看,探索型测试被认为是手工测试的“皇冠”,具有很高的专业性、需要刁钻的思考角度,探索型测试人员常常能发现一般手工测试无法发现的严重问题,因而通常被认为无法自动化。那么事实如此吗?随着AI、AIGC、LLM、计算机视觉(CV)和强化学习技术(RL)的发展,也许有一天探索型测试也能被自动化驱动。
|
||||
|
||||
|
||||
### 16.2.2 一定要自动么?
|
||||
|
||||
在上一小节小陈、木头和老张的讨论中,我们已经可以大致了解自动化测试对于一个开发团队的意义。更确切的说,一个团队要做自动化测试,大多出于以下几个原因:
|
||||
- 提高效率:自动化测试可以自动执行大量的测试用例,比手工测试更快速和高效。它可以在较短的时间内完成大量重复的测试工作。
|
||||
- 提高测试覆盖率:自动化测试可以覆盖更广泛的功能和测试场景,确保系统的各个部分都得到测试。
|
||||
- 提高测试质量:自动化测试可以减少人为错误和疏忽带来的问题。它可以按照预定义的标准和规则执行测试,减少人为判断的主观性。
|
||||
- 提升持续集成和交付能力:自动化测试可以与持续集成和持续交付流程集成,帮助团队更频繁地进行集成和交付,从而加快软件交付速度。
|
||||
|
||||
在考虑一种测试需求或类型是否要自动化、还是采用专职测试人员进行手工测试的时候,我们可以从以下方面综合考虑:
|
||||
|
||||
<img src="img/Slide6.SVG"/>
|
||||
|
||||
此外,测试的自动化还能带来更长远的价值:当我们能利用好自动化实现了软件产品的持续集成和持续测试,下一步的软件测试的工程化就已经初具雏形,可以进而考虑更高集成度的工程系统方案,点亮整个“技能树”:比如考虑利用容器化来构建测试环境,或者引入机器学习来实现测试数据或用例的自动生成。这对一个纯手工的测试团队是无法触达的。
|
|
@ -0,0 +1,100 @@
|
|||
## 16.3 移动应用的自动化测试
|
||||
|
||||
2007年,苹果公司发布了第一代iPhone,开启了智能手机和移动元年,并推出了App Store,成为第一个真正成功的移动应用市场。随后,随着Google Android的入局,移动应用(Mobile Application)市场加速发展。2014年前后,移动手机出货量超越PC;同年,微软提出“Mobile First, Cloud First”战略,强调了移动设备的普及和智能手机的快速发展对于用户的重要性,并通过云计算提供无缝的跨设备和跨平台体验,满足用户在移动环境下的多样需求。随着3G/4G网络的普及,移动市场的用户规模不断增长,并继续扩大其对互联网使用的主导地位。
|
||||
|
||||
移动应用开发也逐步成为软件开发的主旋律之一,新技术层出不穷、百花齐放,从最初的Android的Java技术栈、iOS的Objective-C、和移动浏览器的JavaScript主导,到今天Kotlin、Swift、Flutter、React Native等原生和跨平台技术的融合迭代,移动应用开发依然在快速发展和不断创新。
|
||||
|
||||
### 16.3.1 移动应用自动化测试的特点
|
||||
|
||||
移动应用开发出现在DevOps和敏捷开发理念普及之后,所以自动化测试和持续集成的实践在移动领域成为“标配”和“常规操作”,相应的平台一般都有原生的技术支持。因此,以其独特的复杂性、时代要求,移动应用的自动化测试也呈现出以下特点:
|
||||
|
||||
1. 丰富的平台测试工具:根据移动应用的平台(iOS、Android)和技术栈,选择适合的自动化测试工具。常见的移动应用自动化测试工具包括Espresso、XCUITest、Playwright等。选择合适的自动化测试工具。以下是笔者汇总的常见移动或跨平台测试框架,以及一些基本的参考信息(2023年7月数据):
|
||||
|
||||
| 框架名称 | 支持平台 | 黑盒or白盒 | 所属社区 |
|
||||
| :-------------- | :--------------------------------------------- | :---------- | :-------------------------------------------- |
|
||||
| Espresso | Android | White&Black | Google Android 官方测试框架 |
|
||||
| XCTest | iOS | White&Black | Apple iOS/Mac OS 基于XCode平台的官方测试框架 |
|
||||
| Xamarin.UITest | iOS and Android | White&Black | Microsoft Xamarin跨平台应用技术社区研发和主导 |
|
||||
| Playwright | Cross-browser web应用自动化,移动Web应用 | Black | GitHub 52.6K stars |
|
||||
| Selenium | Web applications and websites | Black | GitHub 21.1K stars |
|
||||
| Appium | Android, iOS, Windows, Web应用 | Black | GitHub 16.6K stars |
|
||||
| Nightwatch.js | Web applications and websites | Black | GitHub 11.4K stars |
|
||||
| Detox | Android, iOS | Gray | GitHub 10.4K stars |
|
||||
| Robot Framework | Web, Android, Windows (with tools lib support) | -- | GitHub 8.2K stars |
|
||||
| Airtest | Android, iOS, Windows, Web(基于游戏场景定制) | Black | GitHub 7.2K stars |
|
||||
| maestro | Android, iOS, ReactNative, Flutter应用 | Black | GitHub 4K stars |
|
||||
| WinAppDriver | Windows App | Black | GitHub 3.2K stars |
|
||||
|
||||
> 可以看到,移动测试框架种类繁多。开发者可以根据自己的平台需求、测试策略、社区活跃度需求等因素进行综合评定,选择最适合自己的。
|
||||
|
||||
2. 考虑跨平台、硬件兼容性:如同浏览器应用需要考虑不同浏览器平台的兼容性,移动应用的自动化测试需要考虑平台系统平台和手机硬件兼容性。相较于苹果设备,安卓平台碎片化更严重(不同的设备型号、操作系统版本和屏幕尺寸),这种系统定制的自由度和体验的碎片化(比如,不同系统的应用权限管理的位置可能各自有一套逻辑),让移动和开发的动开发和测试的复杂性都上升了一个台阶。如果你的应用在需要多个平台上运行(比如同时开发iOS和安卓应用)或使用混合应用开发框架(如React Native、Flutter),那么就更需要确保自动化测试覆盖多个平台和设备。
|
||||
|
||||
> 选择在真机还模拟器运行移动端应用的自动化测试,是一个永恒的问题。真机和模拟器在运行测试方面各有优势。真机往往性能更好、运行速度更快,而且和用户实际体验更为接近。而模拟器定制性强,系统环境干扰因素少,资源权限和灵活度更高;最重要的是成本低,一般无需采购硬件设备。这里笔者的建议是,经费允许的情况下,能选真机选真机,上手更方便,而且优先选择谷歌自家出品的机器,原生支持更好。但如果打算利用灵活度和定制性更高的模拟器,那么自己去调试模拟器也是可以的;有的开发人员把模拟器玩出了花样,做出成熟方案后开公司去了(比如Arnaud在2011年前后创立的Genymotion)。
|
||||
|
||||
3. 移动场景的性能要求:相比于桌面端电脑设备,移动设备的硬件限制和环境变化都会更多。一般而言,移动应用的内存、存储空间、电池电量、网络环境以及CPU占用,都和桌面端、浏览器端的应用在要求上更苛刻。虽然移动端设备的性能,现在正在逐渐追赶PC,手机内存RAM也来到了12GB时代;苹果公司的M系列芯片也下沉到了移动端。但没有发生变化的是,移动设备必须便携和具备持久的续航。而所有的资源消耗,最终都可能会关乎耗电量和设备的续航。
|
||||
|
||||
> 当然,如果有一天手机上可以配备核燃料电池,有取之不尽的电量能源,那么性能消耗也许不再是一个瓶颈;但手机CPU、GPU散热依然会是一个问题,不然会引爆核燃料电池。
|
||||
|
||||
此外,移动场景下的网络环境也更复杂,如果用户覆盖足够广,横跨亚非拉美欧大陆,可以考虑搭建自动化测试能够模拟不同类型的移动网络,例如2G、3G、4G、Wi-Fi和边缘网络,以验证应用在不同网络环境下的表现。
|
||||
|
||||
总之,对于移动应用,性能测试的意义很大,如果能够自动化运行,在开发进程中不断进行自动回归验证,及时发现问题(regression),那么自动化的价值会得到凸显。
|
||||
|
||||
4. 独特的交互方式:移动应用的交互方式与桌面应用和浏览器有很多不同之处,手机大多是通过一块触屏完成几乎所有的交互,此外一部“小小”的手机上还配备着诸多IO(输入输出)设备(麦克风、震动马达、陀螺仪、摄像头等),用于实现不限于多点捏合、拖拽、长按、滑动、震动反馈、屏幕方向感应、语音输入输出、生物信息识别(3D面容和指纹等)、光线感应、运行状态感应等等交互方式。此外,还有基于后置摄像头的扫码、拍照、AR(增强现实)交互等纷繁多样的创新交互;近年出现的折叠屏手机上,连屏幕铰链都成为了交互方式新变量。
|
||||
|
||||
所以,还真的别看手机体型不大,里面的IO设备可着实不少,创意、玩法繁多。有些场景,尤其是基于摄像头的AR、扫码、面容识别等等,不搭建一间测试实验室(Test Lab),提供工业级别的管理,还真的是很难进行全自动化的测试。
|
||||
|
||||
关于移动应用的自动化测试特性,我们不再进一步详细展开。以上四个方面已经概括了软硬件层面绝大多数的特殊性。这些要点即使特性,也引出了移动应用测试的挑战:
|
||||
- 测试本身的稳定性不高(High Flakiness):测试无法在本机上运行,中间依赖的环节多(驱动层、连接层、测试执行层),黑盒多。
|
||||
- 移动测试运行环境特殊(Environment Diversity):需要“跑”在移动设备上,而移动设备是一个广阔的集合,各类系统、各类配置、各类形态。
|
||||
- 几乎无限可能的交互方式(Limitless UX Complexity):移动场景下的交互创新千变万化,层出不穷,为测试带来了新的挑战。
|
||||
- 性能很重要(Performance Matters):测试需要深入的性能层面。
|
||||
|
||||
总之,移动测试需要HELP!接下来,我们将从一个实际的案例出发,尝试将移动应用的自动化测试流程化、体系化,于DevOps开发系统进行集成,给出敏捷开发场景下的综合解决方案。
|
||||
|
||||
### 16.3.2 搭建移动应用自动化测试体系
|
||||
|
||||
搭建一套完整的移动应用自动化测试体系是实现持续集成的重要一环,我们希望借此确保每次代码提交都会触发移动应用的自动化测试,并将测试结果综合分析和反馈给工程系统,在一定的标准上保障代码质量。下面我们将这个体系拆分成关键的模块,然后结合一个移动应用开发的案例,了解其运作方式:
|
||||
|
||||
假设我们正在开发一款新的移动应用。开发者会在**代码仓库**中创建和维护源代码。每当开发者提交新的代码到代码仓库,**持续集成系统**就会自动触发,开始一个新的**构建任务流水线**的“线上任务”。
|
||||
|
||||
构建任务流水线首先会从代码仓库拉取最新的代码,然后在构建任务管理和执行系统的控制下,进行编译、静态代码分析、单元测试等一系列操作,最后生成可部署的应用程序,将其与测试用例、测试需求一起交给**测试管理系统**。
|
||||
|
||||
然后,**测试设备管理平台**会根据需要,为即将进行的测试任务分配合适的测试设备。**测试任务分发和管理系统**会根据预先定义的测试策略,创建并分发各种测试任务。接着,**测试设备和环境控制系统**会根据测试需求,调整设备的状态和环境配置,如网络连接、电池电量、地理位置等。
|
||||
|
||||
一切就位后,**移动设备测试驱动**会启动并运行应用程序,而**测试任务执行器**会按照指定的测试脚本进行操作,如点击按钮、滑动屏幕、输入文本等。在测试过程中,**测试日志和结果记录器**会持续收集和记录应用的运行情况,如运行时数据、错误日志、崩溃信息等。同时,**录屏和截屏系统**会记录应用的视觉表现,以供后续分析。
|
||||
|
||||
所有的测试结果最后会汇总到**测试结果分析系统**进行分析。该系统会识别问题、计算测试覆盖率、性能基准等,并生成测试报告。如果在测试过程中发现了任何问题,测试管理系统会将这些问题发送给**问题发现和跟踪系统**来记录,并追踪其解决过程。
|
||||
|
||||
<img src="img/Slide7.SVG"/>
|
||||
|
||||
利用上面的体系架构,我们可以梳理清楚完整的、现代化的移动测试自动化系统的周期和组件关系,用以支持快速、自动、系统地进行应用测试,确保移动应用的质量。接下来,我们将简单介绍利用开源方案Hydra Lab搭建上述测试管理系统。
|
||||
|
||||
### 16.3.3 使用Hydra Lab搭建移动云测平台
|
||||
|
||||
上文中,我们介绍了一套移动测试自动化的工程方案。其中,代码托管(Code Repo)、测试运行框架(Test Runner/Framework)和持续集成系统(DevOps System or CI/CD System)等部分已经有了非常完善的开源或商业解决方案(Jenkins,JUnit,Azure DevOps等)可供复用。然而,在测试设备管理、测试任务分发和测试任务调度等方面,我们还缺乏一个平台能够帮助我们将这些重要的测试流程服务化,从而真正做到全流程自动化。我们调研了市面上一些比较成熟的商业化移动云测平台。这些平台大都提供了全面的功能,且收取的费用并不高。但是,该领域还没有一个成熟的开源方案能够支持更高程度的测试运行定制化和更灵活的测试设备管理方案。因为手机硬件发布更新迭代快,有时开发者需要将自己手中的定制化测试设备(比如企业定制Android扫码器)或者最新发布的手机接入到测试云服务中,并与DevOps系统联动集成,第三方商业化的平台目前无法提供这样的定制化和安全可控服务。
|
||||
|
||||
微软于2023年初开源了Hydra Lab,填补了该领域开源解决方案的空白。它基于Spring Boot和React构建,支持包括Appium、Espresso、XCTest等多个测试框架,致力于提供一站式的、跨平台的云测试服务。这款框架集成了测试运行部署、测试设备管理、低代码测试等功能,支持Docker部署、开箱即用。Hydra Lab的初衷是为移动跨平台应用的开发团队提供快速、自我管理的云测试基础设施,提高开发效率和质量保障能力。具体来说,借助Hydra Lab,开发团队可以直接利用已经采购的测试设备,搭建一套内部的持续测试的工程化系统,也可以通过配置 Hydra Lab Agent 将自己手头的测试设备接入到已有的 Hydra Lab Center节点上。Hydra Lab目前的主要特性包括:
|
||||
|
||||
1. **分布式测试设备管理**:基于center-agent分布式设计实现可扩展的测试设备管理。
|
||||
2. **测试任务管理**:Hydra Lab提供了全面的测试任务管理功能,方便开发者追踪和调整测试任务的状态和进度。
|
||||
3. **测试结果可视化**:提供测试结果数据图表、录屏展示等。
|
||||
4. **广泛的测试支持**:Hydra Lab支持Android Espresso、Appium、XCTest、maestro,并且借由Appium可以实现更多跨平台(Windows、iOS、Android、浏览器)的测试。
|
||||
5. **智能测试**:Hydra Lab还支持无用例的自动化测试,如Monkey test和智能探索型测试。
|
||||
6. **测试稳定性监控**:Hydra Lab在Docker端集成了Prometheus和Grafana,可以实时监控测试设备状态和测试任务运行状态,支持在测试设备掉线、任务失败自动发邮件报警。
|
||||
|
||||
关于Hydra Lab智能化的探索,以下是一段Hydra Lab开发者团队的自述:
|
||||
|
||||
> 不同于一般的测试框架,Hydra Lab 旨在提供一套测试工程化解决方案,或者说是一套开源云测平台,我们希望它方便地能够与 DevOps 系统、编译系统或 GitHub 等开发工具或平台结合,给开发团队带来低成本的测试全流程方案。同时,我们将智能化引入其中,大家可以在这个项目中看到一些自动化生成测试用例的模块、方案以及相关的prompt。工程化和智能化是Hydra Lab的两个核心关键词,而工程化是智能化赋能的基础,一旦有了工程化的平台,很多痛点的解决方案都可以沉淀在这个平台中。比如,UI自动化测试任务可能会出现一些不稳定的情况,突然找不到某个元素,或者出现一些意外遮挡情况。这种情况下的测试任务失败可能没有反映真实的质量问题。而有了 Hydra Lab 这样的平台级方案,我们可以对这类 flakiness 做识别,重新运行任务,从而提高稳定性。这同时也相当于我们把识别和处理测试不稳定因素的经验沉淀到了Hydra Lab开源工程中,一人贡献,全社区受益。
|
||||
|
||||
搭建Hydra Lab云测平台大致分成三个步骤:
|
||||
- 将Hydra Lab管理中心服务(management center service)的docker image部署到云服务器或者云计算服务容器上。
|
||||
- 在测试机器上启动 Hydra Lab 代理服务(agent service),并将其注册到管理中心。
|
||||
- 通过调用Hydra Lab管理中心服务暴露的 RESTful API 运行测试。
|
||||
|
||||
该平台还提供了一个Uber版本方便一键部署,作为试用体验尝鲜:
|
||||
|
||||
```bash
|
||||
docker run -p 9886:9886 --name=hydra-lab ghcr.io/microsoft/hydra-lab-uber:latest
|
||||
```
|
||||
|
||||
在Hydra Lab服务部署好后,开发者可以通过Hydra Lab提供的Gradle插件或Azure DevOps插件的方式触发测试任务的运行。更详细的内容可以在其GitHub平台上提供的Wiki(https://github.com/microsoft/HydraLab/wiki)上进一步学习了解,包括定制化的功能、部署方式等等。
|
|
@ -0,0 +1,92 @@
|
|||
## 16.4 测试工程化
|
||||
|
||||
有了自动化测试的“能力加成”,整个软件测试过程可以变得更加流水线化(Streamlined)。但是,软件测试是一个涵盖众多测试类型、测试技术的领域,如果在软件生产车间中,从设计到发布上线之间的软件生产流程中,有效的嵌入各种软件测试,使其成为一个有机结合的工程体系,就是我们本节“测试工程化”想探讨的问题。测试工程化是一个在软件工程领域中逐渐发展起来的概念,并不是一个“学术名词”,没有一个公认的“定义”,不过这对于软件开发和测试工程师来讲,完全不是一个问题。
|
||||
|
||||
测试工程化是将软件测试纳入整个软件开发过程中的一种方法,就是为了提高测试效率、质量和可持续性,让产品质量时刻出于验证基线的相对安全标准之内,让大家可以早点安心下班,具备非常实惠和实际的意义。我们先回到本章最初的故事中,体会下测试工程化这个“非学术命题”下,要解决的一些实际问题。
|
||||
|
||||
### 16.4.1 自动化测试体系成形之后
|
||||
|
||||
小陈给Phone Link产品体系搭建起初步的自动化测试之后,和多个功能团队对接, 受到了各路好评,成就感爆棚,心情大好。看到木头在公司的英文名叫Wood,给自己也起了个英文名Nathan,翻译过来叫“内森”,胸有成竹之意,他和木头开玩笑说:“你品品,你细品”。两人正聊着,邻居团队的小郭找过来,说道:
|
||||
|
||||
“小陈,啊不对,内森,咱们现在往主分支里写个代码,合入之前要跑单元测试,还要跑端到端的全量的UI测试,一次验证下来,不算编译都要40分钟,大伙们都有点受不了。”
|
||||
|
||||
“哦?现在要40分钟吗,那再加上编译时间,前后一共要一个多小时了是么?”小陈问道。
|
||||
|
||||
“是啊,有的时候莫名其妙要到一个半小时。有时候等半天跑过了,其他同学过来代码评审提一条建议,这一修改又是等好久,现在PR拖几天进不去是常事。”
|
||||
|
||||
“这问题挺严重,为什么会跑40分钟呢?”小陈沉吟道。
|
||||
|
||||
“我之前在Windows团队,一个验证跑两个小时是常事,为了质量,宁可错杀,不能放过。”木头过来先圆个场,接着说:“小陈你看看,这个40分钟的测试是不是没必要作为每次合入都验证的内容?咱们团队规模也不小,一天30多个pull requests,可能测试系统也负载不过来吧。”
|
||||
|
||||
大家聚到电脑前检查了测试流程,除了1500个大大小小的单元测试,10多分钟跑完;还有30多个“事无巨细”的UI测试用例,平均每个要跑不到1分钟,加起来一次跑20多分钟。大家一起盘了盘这些测试用例,里面有些很基本的验证,也有些很细枝末节的corner case的验证,还包括一些性能验证方面的测试用例。
|
||||
|
||||
“这个测试用例集合里面杂七杂八的用例有点多。”木头说道:“谁没事加了这么多case?有的写的还挺复杂,这函数调用有的我都没见过。”
|
||||
|
||||
“有的是功能团队写功能的时候加上的,还有一部分性能相关的、bug回归测试貌似是实习生小刘加的。”小陈回答:“可能用来检验每个代码改动不太合适。”
|
||||
|
||||
“那是相当不合适!”老张突然出现在围观队伍里,吼了一声,把小陈吓了一跳。
|
||||
|
||||
老张接着说:“高频验证高频,低频验证低频。这里面有的case根本不用放在CI或者BVT里面,后置一些,放到发布前的验收测试都行了。”
|
||||
|
||||
小陈惊叹于老张每次一出口都可以把自己说蒙,好像在听软件开发领域的“道德经”,回过头来愣住盯着老张。木头静静的“欣赏”着两人的互动三秒后,开始继续“破冰行动”:
|
||||
|
||||
“老张讲的过于精辟,很有道理,我来给翻译翻译。”木头稍稍一顿,接着说:“就是说,高频的验证环节应该验证高频的用户场景的用例,比如每次代码合入请求都会触发的验证测试,不太适合验证一些用户低频场景,比如这个用例,打开设置菜单,滑动到底,进入隐私条款,滑到底,打开隐私条款内容等等,这个用例太细致,也是用户使用过程中比较低频的操作场景,放到验收测试或者某些全量回归测试就行。”
|
||||
|
||||
“懂了,所以什么时机做什么测试,是一门学问。”小陈说:“我得把这事情理清楚,回头用一些文档界定一下,不然大家写自动化的测试用例,不清楚放在哪里。”
|
||||
|
||||
“对喽,搞测试工程,要讲究策略的。”老张一副“孺子可教”的样子,继续老气横秋的说道:“质量把控肯定要严格,但是依然要和效率做平衡,每改一行代码都把整个软件颠来倒去测一遍肯定不合适。测试的策略就暗含着对风险的评估,而风险评估又对应着一个产品开发团队的优先级。测试工程里面需要运用多种测试来构建一套在效率和质量平衡点上的体系,让大家可以安心地早点下班,哈哈。”老张说完,一帮人里只有他自己在笑。
|
||||
|
||||
“小陈,咱们这次责任范围可以‘晋级’了,你以后就不只是咱们团队自动化测试的负责人了,是整个测试的负责人了,哈哈哈。”依然只有老张自己在笑,不过这次因为老张在对着小陈说,小陈迫于面子压力也干笑了一声。老张继续说:“你可以把咱们手工测试、工程师内测、alpha/beta用户测试都盘点一下,建立一个工程化的测试体系。”老张是湖北人,心想这事情如何跟九头鸟挂上关系,略微一顿,接着说道“起个名,就叫Hydra Lab,九头蛇,啥都能干,让这些流程Just In Time,岂不妙哉。”
|
||||
|
||||
小陈知道老张说的很有道理,“Hydra Lab”也听起来是个很棒的名字,不过对于他画的这个“大饼”的确有点吃不消。木头又一次加入到讨论中,几人转战食堂饭聊,逐渐越扯越远:“就说不远的未来,有一个办公楼里一个人影没有,不开灯,只能看见几个亮着的屏幕、听见机器嗡嗡作响。全自动写代码!几个不同人格的AI自己开发自己测,自己发版自己上线,你说吓不吓人。”“吓人,太吓人了。”“好孩怕。”“全是小陈搞出来的,人家从测试发家,搞自动化、工程化、智能化,再从测试驱动开发,最后赢家通吃了。”“太强了,给大佬夹菜,求带!”“你们可太能扯了,逗死我了。”几个人聊得好不风趣。
|
||||
|
||||
### 16.4.2 测试工程化要点分析
|
||||
|
||||
测试工程化的概念是建立在现代软件工程的敏捷开发、DevOps等理念之上的,综合了测试策略、自动化测试、持续集成和持续交付、质量度量等方面,是将测试纳入软件开发全程的方法,力图为软件开发提供可持续的、高效的质量保证。
|
||||
|
||||
至于如何纳入,首先,测试和验证的流程应该和“变化”绑定,这种变化不止于代码修改,还可能包括:
|
||||
- 上线和发布:软件交付给一个用户群体。
|
||||
- 版本变化:比如线上用户软件从v1升级到v2。
|
||||
- 做实验:一个新的功能开启。
|
||||
- 内部依赖变化:把类库从1.1升级到1.2。
|
||||
- 外部平台的变化:比如用户的设备操作系统大范围从Windows 10升级到11。
|
||||
|
||||
等等,总之,变化可能不止源于自身,有可能来自软件的“四面八方”。而这些变化隐含了风险。任何成功的测试工程化流程都需要一个明确的测试策略和计划。这涵盖了确定测试目标、范围和优先级,并根据项目需求以及风险评估来确定测试的重点和覆盖范围。
|
||||
|
||||
此外,重复性任务和回归测试通过编写可靠的自动化测试脚本进行自动化,然后这些脚本将集成到持续集成和持续交付(CI/CD)流程中。测试环境和数据管理也是必不可少的。需要建立适当的测试环境,包括硬件、软件和网络配置,并对测试数据进行有效管理,如数据准备、数据脱敏和数据回滚。一旦测试环境和数据准备好,测试便可以集成到CI/CD流程中。这确保每次代码提交都会触发相应的测试,并将测试结果反馈到版本控制系统和构建工具中。
|
||||
|
||||
与此同时,测试人员、内测团队(如运营人员)应与开发人员紧密合作,响应反馈,进行持续集成、测试优化和缺陷修复。测试工程化流程还应包括持续监控和反馈机制,例如建立监控和日志系统,以便收集和分析生产环境中的运行数据和问题,提供反馈,并及时发现并解决性能问题和异常。如果有条件有需求,还可以制定质量度量和报告标准(Baseline),用于对测试结果和软件质量进行定量评估,并生成清晰的测试报告以供决策者参考。适当的培训和知识分享、建立适当的文档和知识库也大有裨益。
|
||||
|
||||
总结起来,测试工程化是一个复杂命题,但和软件工程的各方面相呼应,而且越来越模式化。笔者认为,最终和AI、机器学习的融合是不可避免的,,测试团队应该保持密切关注,能掌握和应用起来是最好不过的。
|
||||
|
||||
#### 16.4.2.1 “Just In Time”的自动化测试
|
||||
|
||||
自动化测试可以在软件开发的多个阶段被引入,“纳入”的时机安排原则上和“测试金字塔”的理念很相似。测试金字塔原则大致可以描述为,根据测试覆盖范围和稳定性的不同,将测试分为不同层级,形成金字塔形状。底层是单元测试,中层是集成测试,顶层是用户界面测试。金字塔原则鼓励更多的测试放在底层,减少顶层的测试,以提高测试速度和稳定性。以下简单罗列一些常见的自动化测试类型,以及它们可以接入的开发阶段和时间点:
|
||||
|
||||
1. **单元测试**:一般每当代码有任何变化,例如新增或修改代码时,就可以触发全量的自动化单元测试。目标是确保每个代码单元(如函数或方法)按照预期进行工作。
|
||||
2. **集成测试**:简言之,当单个代码单元被组合在一起时,进行跨单元或模块进行的测试就叫集成测试,用以检测不同组件间的交互是否存在问题。集成测试可以每次提交代码时自动运行,也可以定期运行。
|
||||
3. **冒烟测试**:冒烟测试目标是看看改了之后还能否“通电冒烟”,确认新的改动没有破坏软件的基本功能。通常在每次构建后进行,称为BVT(Build Validation Test)。
|
||||
4. **性能测试**:通常在BVT之后或者和回归测试并行进行,目标是评估软件系统的性能表现。有时会结合一些压力场景进行,也有通过一些“长途测试”(Long-haul Test)来暴露问题。通常在每个主要的版本发布前,或者当系统架构发生重大变化时进行。
|
||||
5. **回归测试**:当系统中有新的功能添加或者现有功能被修改后,进行回归测试。目标是确保这些更改没有引入新的错误或重新引入旧的错误。可以在每次构建后或部署前进行。
|
||||
6. **验收测试**:验收测试的目标是全面验证软件系统是否满足业务需求和用户期望。在每个冲刺结束时或新版本发布前进行。
|
||||
|
||||
<img src="img/Slide8.SVG"/>
|
||||
|
||||
每个测试类型的频率可能会根据项目的具体需求和实际情况进行调整,要综合评估投入产出比ROI,测试用例的覆盖情况、被验证功能的优先级和就近原则:什么被修改了、什么可能受到影响了,就着重测试什么。这个刚刚故事里,老张提到的“Just In Time”的测试很像,但在一个代码行数百万级的复杂的软件系统中,即使在设计层面无论多么“松耦合”、“幂等”,“通过修改的内容去推断出什么测试需要被运行”依然是一个终极难题,这已经超越了白盒视角,来到了“上帝视角”:需要全面分析软件内部的依赖关系、逻辑路径和演进情况。这也许真的是一个AI才可能解决的问题。
|
||||
|
||||
<img src="img/Slide9.SVG"/>
|
||||
|
||||
#### 16.4.2.2 软件自测和内测
|
||||
|
||||
软件的自测和内测的含义没有公认定义。在本章节中,统一口径为:自测指开发团队自己对自己开发的产品进行测试的过程,内测指开发团队请自己的软件社区内部用户进行测试的过程。本章最初假定了软件自动化测试是指测试全流程的自动化,那么自测和内测,也可以作为测试工程化的一部分,并进行一定程度的自动化。
|
||||
|
||||
上一章中,我们提到,在微软,团队自测和号召公司同事试用和自测软件,几乎已经成为了微软质量控制流程和文化的一部分,这样的活动一般叫做Self-hosting或Bug Bash。同时,在上一章我们也已经提到了一些活动组织的技巧和提高测试效率的技术手段,这里不再赘述。其实鼓励参与感和方便的工具、友好的测试环境搭建指南是最关键的,让大家快速上手、乐在其中、有获得感。这类活动一般可以定期举行,也可以在特定时间点(如功能实现完成后,Code Complete之后)进行。另外,工程师在开发过程中自己写的单元测试、集成测试,也是自测的重要部分。
|
||||
|
||||
软件内测,也称为Beta测试,是指在软件正式发布之前,将软件提供给一部分用户进行测试的过程。这样可以让开发者及时发现并解决软件中的问题,提高软件质量。内测用户群体通常是由开发者或公司组织和维护起来的,也有用户自发形成的。他们会在使用过程中反馈问题和建议,帮助开发者改进产品。其中的一些技术要点包括:
|
||||
- 招募测试用户:招募一组用户来测试软件,包括目标用户和广泛的用户群体,并建立面向他们的软件分发渠道。
|
||||
- 部署测试版本:向测试用户分发软件的测试版本,让他们在真实环境中使用和评估软件。
|
||||
- 收集反馈:设置问题反馈渠道,并能通过该渠道收集到详细的诊断报告,如Bug报告、错误信息、堆栈信息等。
|
||||
- 问题追踪和管理:建立问题追踪系统(如Jira、GitHub Issues、Azure DevOps Bug)来记录和跟踪测试用户报告的问题,并确保问题得到适当的解决。
|
||||
- 修复和更新:根据测试用户的反馈和问题报告,修复软件中的问题,并更新软件版本。
|
||||
|
||||
有些面向国内软件的内测用户依靠QQ群来维护,分发就是想群里发安装包文件,如果用户一侧发现了软件崩溃,也是让用户把堆栈提取出来,以文本的形式发消息到群里,这就比较原始,自动化和工程化程度不高;对于“小”软件、“小社群”也许简单有效,但如果是管理上万人的内测社群,就非常吃力了;这时我们可以依赖软件分发平台来向对应渠道的用户提供内测版本,比如Microsoft Store的分发平台就原生支持Flight 航道的功能,可以定义航道的优先级和目标用户,实现多渠道分发。
|
|
@ -0,0 +1,90 @@
|
|||
## 16.5 从自动到智能
|
||||
|
||||
2023年是人工智能发展的有一个里程牌年份,ChatGPT横空出世,再次点亮了AI赛道曙光。在这个智能化加速的时代,软件应用的广泛普及和不断增长的软件复杂性对软件测试提出了更高的要求。过去几十年,我们目睹了软件测试的自动化发展。然而,随着人工智能(AI)和生成式人工智能(AIGC)的快速发展,软件测试被智能赋能成为了一个必然的方向,很多企业和开发团队已经走在探索的道路上。
|
||||
|
||||
回顾过去,软件测试的自动化已经极大地改善了测试效率和质量。自动化测试工具和框架的出现使得测试人员能够快速执行大量的测试用例,减少了手工测试的繁琐工作。然而,随着软件系统越来越复杂,测试环境的多样性增加,传统的自动化测试面临着挑战,如UI变化频繁、新功能的探索性测试等。强化学习、生成式AI、AIGC以及各类Copilot“副驾驶”工具、Auto-GPT、LangChian等相关技术的飞速发展,使得在AI赋能下提高测试的全面性和深度具备更高的可行性,为软件测试带来了新的机遇和可能性,包括且不限于以下方面:
|
||||
|
||||
- 测试环境的模拟生成。
|
||||
- 测试数据生成。
|
||||
- 智能探索型测试。
|
||||
- 测试用例生成和优化。
|
||||
- 测试结果分析解读。
|
||||
- 测试智能调度和重试:提升运行稳定性提升。
|
||||
- 基于测试结果的诊断建议。
|
||||
- 对话式测试体验的构建。
|
||||
...
|
||||
|
||||
未来,随着AI技术的不断进步和应用,智能化将在软件开发生命周期的各个阶段发挥更大的作用:一方面,借助一些基于LLM技术下的软件测试场景的prompt engineering技术,智能化测试将推动自动化测试更加自动;另一方面,软件测试也在从自动化时代迈向智能化时代,“测试智能体”将有能力更好地理解和分析软件系统(从代码到界面、白盒到黑盒),从大规模的测试数据中挖掘出隐藏的缺陷模式和异常行为,降低自动化测试用例的维护成本,进一步减少测试人员的工作量和时间成本。
|
||||
|
||||
总之,我们可以期待智能化测试在未来的软件开发中发挥更重要的作用。接下来,我们将在有限的篇幅里展开探讨几个智能测试的想法和实践探索,启发读者在该领域前行成为先驱(trailblazer)。
|
||||
|
||||
### 16.5.1 智能探索型测试
|
||||
|
||||
用手工方式对软件进行的黑盒UI测试是笔者认为测试这个领域内最接近用户视角的方式。这种方式既可以非常按图索骥,也可以是充满创造性的探索型测试。在2010年前后微软团队出品的《探索式软件测试》这本书中,讲这种测试的深入剖析出了哲学的意味,提出多种不同思路(Money Tour卖点漫游, Landmark Tour地标漫游, Obsessive-Compulsive Tour强迫症式漫游, Saboteur破坏性漫游等等)的漫游测试,来快速穷尽用户视角下的应用使用路径、用户场景,暴露问题。在自动化测试中,有一种类型的测试叫随机测试,其英文是Monkey Test,执行测试的是一只猴子。这来源于想法“如果让一百万只猴子在一百万个键盘上敲一百万年,从统计学角度,他们最终就可能写出莎士比亚的话剧”。当我们大量执行随机测试的时候,就是在应用这种“猴海战术”。
|
||||
|
||||
但试想,如果这个猴子聪明一点,能理解应用程序的界面或者接口,并能实施相对合理的交互,是不是不一定要依赖“猴海战术”,可以在更短的时间内发现问题?在人工智能、机器学习、大语言模型快速发展的今天,更聪明的猴子已经成为可能。智能探索型软件测试具有以下优势:
|
||||
- 自主学习能力:测试代理通过强化学习算法不断优化测试策略,提高测试效率和准确性。
|
||||
- 自动化和持续性:智能测试代理可以自动执行测试,并且可以持续地进行测试,减少了人工测试的工作量和时间成本。
|
||||
- 边界情况探索:通过探索系统的边界情况和异常情况,智能测试代理能够发现更多的错误和潜在问题。
|
||||
|
||||
智能探索式测试的可行思路是利用计算机视觉、屏幕元素识别和自然语言处理的技术,解析和理解屏幕上的元素或者程序接口的语义,然后做出交互动作。这是一种黑盒视角的智能测试,基本的思路为:
|
||||
1. **Start**:启动软件和测试智能体。
|
||||
2. **Extraction**:提取软件UI、接口信息(API描述、UI截图以及DOM元素信息)。
|
||||
3. **Comprehension**:识别软件界面或交互接口,运用模型进行理解,得出解析值(向量)。
|
||||
4. **Decision**:将识别结果(即解析值,也或包含动作历史、反馈信息)向量交给决策模型,得出动作向量。
|
||||
5. **Action**:执行动作向量中描述动作。
|
||||
6. **Evaluation**:执行动作后触发软件变化(也可能没有变化),然后重复2。
|
||||
|
||||
<img src="img/Slide10.SVG"/>
|
||||
|
||||
这是笔者团队提出的简单流程,该抽象模型很像马尔科夫决策过程中涉及的概念:决定下一步动作(Action)或策略(Policy)的包括当前的状态(State),也可能会包括之前的路径轨迹(Trajectory)。但是这个问题和强化学习所要解决的问题可能并不完全相同。探索性测试可能是有多元目标的,而其中对于测试覆盖率的追求,是一个很复杂的指标:对于测试智能体而言,我们可能无法事先知道应用内有多少状态、多少界面,甚至开发团队也不清楚。因此这比一般的强化学习问题更复杂,我们很难设计出合理的反馈函数,使得模型收敛。而即使一个模型针对于一个应用收敛了,对于一个全新的应用又可能遇到截然不同的情况。以强化学习和图像识别为驱动的黑盒视角下的智能探索型软件测试是一种新兴的测试方法,把应用程序当做“游戏”来“玩”和探索,在这种测试方法中,强化学习被用作一种自主学习的方法,使软件测试代理能够通过与系统进行交互来学习和改进测试策略。这样的想法在很多学术研究机构和大学的论文中也有论述,但目前还没有看到成熟的可以应用于软件工业领域的完整方案。
|
||||
|
||||
此外,智能探索还有更简单的思路,即把应用内部的状态跳转看做一个状态转换图(State Transition Graph),然后采用深度优先或者广度优先的基本思路去遍历这张图。这种方法简单可行,相当于简化了上文提到的Decision决策的步骤,采用了基于简单策略或规则的方式选取元素进行交互,使得探索的过程可解释性更强,灵活度更高。
|
||||
|
||||
总体而言,采用模型进行决策的思路(Model-based)更接近“聪明的猴子”的概念,而采用固定策略、算法或规则(Rule-based)更可控、更容易实现。此外借助于近期的LLM、ChatGPT的快速发展,我们是否可以借助他的力量,提出更有趣的方向:LLM-based动作决策体系?或者,结合LangChain等相关技术,当我们可以把软件接口表示(比如DOM文本、截屏图像向量),序列化成prompt的时候,上述Comprehension的流程是否也可以让LLM参与进来?这两个问号就留给读者进行探索了。
|
||||
|
||||
### 16.5.2 测试用例生成
|
||||
|
||||
在大语言模型的赋能下,白盒测试视角的测试用例生成,尤其是针对局部、单个类的单元测试用例的生成,已经非常成熟了,一些常见的思路如下:
|
||||
|
||||
1. **生成测试用例描述:** 可以让模型帮忙生成特定函数或方法的测试用例描述。
|
||||
2. **生成测试代码:** 对于一些常见的编程语言,如 Java、Python 或 JavaScript,你可以告诉模型直接生成可执行的测试代码。
|
||||
3. **提供测试覆盖率建议:** 还可以让模型生成关于如何提高测试覆盖率的建议。我们可以给大语言模型一个已有的测试套件,并让模型给出增加测试覆盖率的建议。
|
||||
4. **边界条件检查:** 模型可以用来生成针对特定函数或方法的边界条件测试。
|
||||
5. **生成异常测试用例:** 模型可以用来生成检查特定函数或方法异常行为的测试用例。
|
||||
|
||||
这方面比较流行的ChatGPT、GitHub Copilot已经非常成熟,读者可以用自己手头的代码试下,提示词一般形如“针对如下由三个破折号分割的代码内容,请生成若干单元测试,提供较高的测试覆盖率:---<代码内容>---”。这里笔者就不再举例赘述。可以看出来,这种方法的最大限制来自于提示词Token数量的上限,在代码体量较大的情况下,想生成高质量的跨模块的集成测试代码基本很难实现。
|
||||
|
||||
此外,我们是否有可能利用大语言模型的特性,辅助黑盒视角的测试用例生成?我们以移动应用的UI测试为例,探讨一些可能的思路。上文的智能探索测试的讲述中,我们提出应用内部的状态跳转看做一个状态转换图(State Transition Graph),那么如果我们可以通过智能探索测试绘制出这张状态转换图,再通过一定的剪枝算法将其转化为树的数据结构,我们就可以以叶子节点作为一个用户场景、测试用例的终点,将交互的路径作为测试用例序列化出来。
|
||||
|
||||
我们前面小节提到的 Hydra Lab 就对这一思路进行了实现,总结来讲就是:先探索,再利用。先通过一些策略探索和漫游一个软件,然后转换理解,形成数据结构,即“状态转换图”,最后再利用这些结构化的数据,作为后续探索和用例生成的基础。这就相当于,对软件黑盒内部逻辑进行了总结提炼,完成了一次“有损压缩”。这也很像一个测试人员第一次用一个软件,一定会先探索理解,同时在旁边整理一个信息图,这在测试领域被称为“功能图”或“状态图”,然后再设计用例;这非常自然和接近人的操作。如果我们能用计算机做这件事情,就能自动化地完成探索,绘制状态图,并生成测试用例。
|
||||
|
||||
最后,我们可以把这个信息作为prompt提示词的一部分来利用大模型进行用例生成,整个过程充分自动化和智能化,仅需要较少人工干预对生成的内容进行校验和调试,这也能让相应的测试用例、测试流程随着应用内部的变更进行调整和兼容。
|
||||
|
||||
### 16.5.3 测试结果分析
|
||||
|
||||
软件测试的一大挑战在于测试结果的解读和分析。以用户界面(UI)测试为例,一次测试的运行可能会产生大量的应用日志内容、捕获测试异常信息、生成测试的最终结论。在UI测试过程中,为了更好地理解测试过程和结果,我们甚至可能会截取软件的屏幕图像或录制整个测试过程的视频。简而言之,测试过程会产生海量的诊断信息和数据。
|
||||
|
||||
现在,问题来了:能否利用大语言模型的能力,深度分析这些庞大数据中的异常情况,为我们提供明确的结论?LLM能否告诉开发者这次测试的异常是源于哪个模块,以及如何修复它?更进一步,能否在分析代码的同时,给出一些具体的修复建议?这些都是我们需要探索的问题。整体来看,我们认为测试结果分析和大语言模型的结合,可以从以下四个方向进行深入探索:
|
||||
|
||||
1. **测试异常可靠性推断:**通过大语言模型的分析,我们可以对测试结果的可靠性进行推断,理解测试异常是否是偶发事件、被测应用的Bug,还是存在其他系统性的问题。
|
||||
2. **测试失败原因分析:**大语言模型可以帮助我们理解测试失败的原因,从日志中提取关键信息,定位出导致问题的代码模块,甚至是具体的代码行。
|
||||
3. **测试失败修复建议:**结合源代码分析,大语言模型可以为开发者提供针对性的修复建议,从而帮助他们更有效地解决问题。
|
||||
4. **性能测试数据分析、异常检测:**对于性能测试,大语言模型能够分析大量的性能数据,检测出性能的瓶颈,提供优化建议。
|
||||
|
||||
总的来说,大语言模型在处理复杂、多源的测试数据方面有着天然的优势,如果我们能有效地利用这些优势,相信能够为软件测试带来实质性的提升。
|
||||
|
||||
### 16.5.4 智能测试:以AI为对象的测试
|
||||
|
||||
咬文嚼字地讲,智能测试和测试智能化是两个截然不同的概念。智能测试,或者说智能体测试是指对AI、智能体、机器学习模型或智能应用进行测试,验证其有效性、召回率等指标的测试,这是一个近年来逐步受到越来越多关注的新兴方向。以下是针对人工智能(Artificial Intelligence,AI)、智能体、机器学习(Machine Learning,ML)模型等智能应用的测试,存在一些前沿实战和技术:
|
||||
|
||||
1. 数据集测试:测试训练数据集和测试数据集的质量、多样性和覆盖度,以确保模型在各种情况下具有良好的性能。
|
||||
2. 边界条件测试:测试模型在边界条件和极端情况下的行为,以评估模型的鲁棒性和稳定性。
|
||||
3. 强化学习测试:针对强化学习算法和智能体的测试,包括对策略、价值函数和环境模型的验证和评估。
|
||||
4. 可解释性测试:测试模型的解释能力和可解释性,以理解模型的决策过程和推理过程。
|
||||
5. 对抗性测试:随着对抗性攻击的出现,对抗性测试变得越来越重要,用于评估模型的鲁棒性和安全性。
|
||||
6. 自适应测试:随着模型的在线学习和自适应能力的增强,测试需要考虑模型的持续更新和迭代过程。
|
||||
7. 对抗性测试:通过构造对抗性样本或攻击来评估模型的抗干扰能力和安全性。
|
||||
8. 模型评估和验证:使用评估指标和度量标准来评估模型的性能、准确性、召回率、精确度等。
|
||||
|
||||
目前,随着人工智能和机器学习的广泛应用,对智能应用的测试需求越来越重要,我们既要保证其能满足用户需求,还要保证构建 Responsible AI,即可信人工智能。研究者和学术界也在积极探索新的测试技术和方法,以应对智能应用的特殊要求。该领域挑战之一是测试数据的获取和准备,这些数据代表了正确价值的导向,是评价标准的核心。
|
|
@ -0,0 +1,34 @@
|
|||
|
||||
### 思考与练习
|
||||
|
||||
1. 自动化测试可以完全替代手工测试吗?手工测试的优势有哪些?
|
||||
2. 让一个手工测试的团队开始逐步践行自动化测试,需要做好哪些准备工作?
|
||||
3. 你能从技术栈、测试方法的角度谈谈服务端的自动化测试和客户端的自动化测试有什么不同吗?移动应用的自动化测试有什么新特点?
|
||||
4. 如何理解测试工程化?测试工程化和智能化的关系是什么?
|
||||
5. 人工智能技术可以从哪些角度赋能自动化测试?
|
||||
6. 以下关于软件测试的想法,你认同吗?为什么?
|
||||
- 写测试用例必须根据spec,所以是很机械的。
|
||||
- 自动化测试没什么技术含量。
|
||||
- 测试人员不需要写代码。
|
||||
- 用Debug版本测试更容易发现问题。
|
||||
- 大公司都是自动化测试。
|
||||
- 在实际环境中的测试效果最好。
|
||||
- 这个版本改动不大,随便测一下局部功能就可以了。
|
||||
|
||||
### 参考资料
|
||||
|
||||
[1] 《构建之法》,邹欣,人民邮电出版社
|
||||
[2] 《微软的软件测试之道》, Alan Page / Ken Johnston / Bj Rollison著,张奭 / 高博 / 欧琼 / 赵勇译,机械工业出版社
|
||||
[3] 《软件测试之困:测试工程化实践之路》,肖利琼,人民邮电出版社
|
||||
[4] 微软开源智能云测试平台 Hydra Lab,GitHub,https://github.com/microsoft/HydraLab
|
||||
[5] 打造更聪明的猴子:开源云测框架 Hydra Lab 的智能化测试实战,InfoQ,
|
||||
https://www.infoq.cn/article/YaUjY3klLG6iT7cWvPAy
|
||||
[5] Playwright enables reliable end-to-end testing for modern web app, https://playwright.dev/
|
||||
[6] Appium Documentation, Appium, https://appium.io/
|
||||
[7] Xamarin.UITest, Microsoft Learn, https://docs.microsoft.com/en-us/appcenter/test-cloud/frameworks/uitest/
|
||||
[8] State of Testing 2023, PractiTest,https://www.practitest.com/state-of-testing/
|
||||
[9] Reinforcement Learning for Automatic Test Case Prioritization
|
||||
and Selection in Continuous Integration, Helge Spieker / Arnaud Gotlieb / Dusica Marijan / Morten Mossige, https://arxiv.org/pdf/1811.04122.pdf
|
||||
[10] Exploratory Performance Testing Using
|
||||
Reinforcement Learning, Tanwir Ahmad, https://ieeexplore.ieee.org/document/8906705
|
||||
[11] How can AI and ML help you design better exploratory testing scenarios? Linkedin, https://www.linkedin.com/advice/0/how-can-ai-ml-help-you-design-better-exploratory
|
После Ширина: | Высота: | Размер: 81 KiB |
После Ширина: | Высота: | Размер: 73 KiB |
После Ширина: | Высота: | Размер: 55 KiB |
После Ширина: | Высота: | Размер: 42 KiB |
После Ширина: | Высота: | Размер: 69 KiB |
После Ширина: | Высота: | Размер: 76 KiB |
После Ширина: | Высота: | Размер: 67 KiB |
После Ширина: | Высота: | Размер: 76 KiB |
После Ширина: | Высота: | Размер: 67 KiB |
После Ширина: | Высота: | Размер: 96 KiB |
|
@ -0,0 +1,3 @@
|
|||
# 第十七章 质量保障
|
||||
|
||||
前两章,我们探讨了软件测试的涵义、重要性和技术手段,这个领域可谓包罗万象。然而,站在软件质量的高层次视角上看,软件测试只是一种手段,保障软件的高质量才是最终目的。本章,我们依然将以一个源自真实开发场景的故事开启对软件质量保障的探讨,力图帮助大家理解软件质量保障的含义、意义,并探讨一些常见举措和未来展望。
|
|
@ -0,0 +1,71 @@
|
|||
## 17.1 发版“作战室”的故事
|
||||
|
||||
发版“作战室”,也就是Shiproom,在微软指软件发布的决策会议、讨论室,主要产品经理或项目经理,研发负责人、功能负责人,一起探讨当前周期结束后,基于目标版本代码“快照”构建出的软件产品,是否符合预期和可以通过质量评估,进一步上线发布。该会议具有很重要的“战略意义”,所以笔者将Shiproom翻译成“作战室”。
|
||||
|
||||
### 17.1.1 “作战”会议上的讨论
|
||||
|
||||
近来,木头在团队里承担了一项新角色,由于他对团队产品代码和开发协作的方方面面都沉淀了很多经验,领导推荐木头担任产品的发版主持人,英文叫Shiproom Owner,相当于这个作战室的指挥官或者核心参谋的角色。
|
||||
|
||||
今天上午9点55分,木头提前来到会议室,打开会议大屏幕,将产品上线进度仪表盘投影到屏幕上,为这次的Shiproom会议做准备。目前团队的产品是双周上线一个包含新功能“大版本”,包含修复的“小版本”采用灵活上线的策略,质量达标就可以随时上,所以这个会议每周三次,没有版本变得的时候后就跳过。不一会儿,产品经理兼项目经理大刘(TPM,Technical Programme Manager),新功能负责人小李,工程质量负责人小陈,项目研发经理老付,陆陆续续来齐聚会议室。
|
||||
|
||||
"大家上午好,目前各位可以看到仪表盘上显示,咱们有4个版本在不同的环境运行,V1.2.2在内部自测环境上线到百分之20%,V1.1.15目前在Alpha环境全量上线,V1.1.14在Beta环境上触及到30%的用户,生产环境上全量是V1.0.9。" 木头开始引导会议。
|
||||
|
||||
“小李,请你先来介绍一下V1.2.2的新特性吧。”木头看向了新功能负责人小李。
|
||||
|
||||
小李报告道:“我们添加了一些用户体验的优化措施,并增强了一些功能模块,另外有一位研发同学帮忙优化了软件的CPU占用。”
|
||||
|
||||
木头点点头,又看向了小陈,“小陈,你可以给我们汇报一下,这些版本的综合质量情况吗?"
|
||||
|
||||
小陈说道:“对于V1.2.2,我们已经完成了大部分的自动化的功能和性能测试,但是我们在一项功能中发现了一个比较严重的bug,我们看到有一定的几率,大概每3到4次性能测试中,有一次能触发应用在这个新功能方面的OOM。”小陈提到的OOM是指Out Of Memory,即软件的内存使用超出了软件运行环境的内存使用上限。
|
||||
|
||||
木头皱了皱眉,“嗯,这个问题挺严重。小陈的建议是什么?”
|
||||
|
||||
小陈回答:“我建议我们内部自测环境先回滚一个更健康的版本上,这个环境下也有300多个用户。然后我们可以把修复bug的任务优先级提高,尽快修复。”
|
||||
|
||||
木头点了点头,“好,这个bug貌似在仪表盘上显示出来了,但是还没有在最高的优先级。”木头又看了一眼旁边大屏幕上的上线仪表,由于这个bug目前定的是P2,所以没有影响这个版本的健康状态,仪表盘上还是“形势一片大好”的绿意盎然(绿色代表版本质量状况是“健康”)。“可能百分之30左右的复现概率有点高,老付,你对这个bug有什么看法?”
|
||||
|
||||
老付沉思了一会儿,说:“这个bug会前小陈发出来了,我们有在看,之前版本没见过这个问题,所以还真的是有可能是一个regression。目前还没有最终的原因分析结论,但是我觉得调高这个bug的优先级没问题,先定为P0的问题吧,不修复没法继续上线。”
|
||||
|
||||
“OK,谢谢老付和小陈的支持。”木头说,“那我们先把这个bug优先级调一下吧。”
|
||||
|
||||
“改好了。”小陈说,他是会议现场“唯二”带着笔记本的,木头也在用笔记本投屏。不过小陈眼疾手快地打开bug直接调整了优先级,接着说:“你刷新一下仪表盘看看。”
|
||||
|
||||
木头猛按了一下F5,“上线仪表盘”网页刷新了,最新的OOM bug按优先级排序跃升已知bug榜单第一名,同时bug关联的版本所属内部自测环境“Team Ring”由绿转红,描述符由“Healthy”转为“Blocking”(上线受阻)。
|
||||
|
||||
“这个看着挺吓人的哈,是不是内部自测用户也有爆出这个问题的?有没有影响他们体验?”木头问道。
|
||||
|
||||
小陈说:“这个bug用户可能不太容易察觉到,相当于应用程序在后台的时候会默默‘死掉’,导致新功能不能用,但是在前台的时候可能感知不到。”
|
||||
|
||||
“了解,但是这个问题肯定要在1.2版本解决,不然新功能挂了就白上了。”木头说:“可能老付这边看看这个问题,后续找到原因和方案也和大家分享下。”
|
||||
|
||||
“没问题,我们研发后面举行一个‘Postmortem’,回顾和总结一下这个问题。同时我们看看是否可以在开发过程中、持续集成流程中,引入相关的代码审查、静态代码分析和单元测试,争取让它‘Fail Fast’。后面如果这个问题复现有难度,还要小陈协助下。”
|
||||
|
||||
“好嘞,没问题。”小陈回答。
|
||||
|
||||
“大刘,咱们目前的版本上线处理,有没有建议?”木头最后看向了大刘。
|
||||
|
||||
大刘回答:“嗯,1.2.2有问题那先回滚到上一个没问题的版本吧,貌似要回滚到1.1.15?。”
|
||||
|
||||
“对。”木头回答。
|
||||
|
||||
“好的。后面这个新版本修复了也请告诉我一下,我们有外部的合作客户很期待1.2版本的新功能。另外,既然每次测试可以发现一些问题,我们是否可以优化一下流程,小陈那边全测试完毕后再开始内部自测环境上线,毕竟咱们自测的用户都是同事,他们的体验也要重视。”大刘提议到。
|
||||
|
||||
“我没意见,可以的。”小陈听到要把自己QA的流程进一步前置,觉得机会很好,马上表示赞同。
|
||||
|
||||
木头说:“嗯,这个议题可以讨论,内部自测用户群20%上线和QA自动化回归测试同步进行,我是知道之前咱们把这两件事并行的考虑,主要是考虑到自动化测试还有一些不稳定因素,有时候报出的问题不一定准确,就用内部自测的用户运行情况做一个佐证。咱们会后讨论一下这个事情,现在先看看关于上线,各位同学还是否有其他问题。”
|
||||
|
||||
“Beta环境的1.1.14版本貌似有一个corner case的问题要修复对吧,影响千分之一的用户,目前在1.1.15修复了。”大刘问道。
|
||||
|
||||
老付接下话茬:“是的,我们在beta环境看到有很少的用户报出这个问题,但这个如果上线到生成环境,会影响生产环境300多万用户的体验以及相关量化指标,所以及时进行了修复,把修复的改动从主分支迁移到了相关上线分支,1.1.15目前看不到这个问题了,而且1.2的版本以及后续的版本都会包含这个修复。”老付转头对木头说:“木头,咱们1.1.15是不是就可以上beta了。”
|
||||
|
||||
“对,这么重要的话题我差点忘了。我会后就操作上线,需要老付和大刘你来在系统上审批通过下。”木头看到仪表盘上显示,Alpha环境的1.1.15版本已经在这个环境下停留了5天,有2000多日活用户,没有新增问题,数据指标都比较稳定,觉得有把握继续上线。
|
||||
|
||||
“好的,没问题。”大刘和老付回答道。
|
||||
|
||||
“应该没有其他议题了,感谢各位参加!有相关问题随时找我。”木头一场紧张刺激的发版大作战会议就这样结束了。
|
||||
|
||||
### 17.1.2 软件发布和软件质量
|
||||
|
||||
一个成熟的开发团队,软件发布的过程应该是对全团队透明的,一个新版本最终一步步上到生产环境,是整个开发团队辛苦工作开花结果的过程,尽管这个过程包含着机遇与风险,但一旦顺利达成,是一件非常值得庆祝的事情。“Ship it!”是一句令人兴奋和期待的口号。
|
||||
|
||||
相应地,一旦失败,一个重磅的漏洞或bug逃过了层层检测,落到了生产环境,由线上用户报出来反馈给媒体,那就不是开花结果,而是“落地大瓜”。打击整个团队的信心,危及到产品的成败。对于产品负责人和决策者,一方面要重视软件质量保障,未雨绸缪,防微杜渐,重视代码质量和相关流程的完善,把这种文化推广到团队;另一方面,要鼓励大家把看到的问题讲出来,并用一些量化的可视化工具呈现出来,勇于面对问题,而不是回避遮掩,还原和讲出质量“真相”。质量的保障,工具和自动化可以帮助加速,但最终落在每一个团队伙伴对质量的追求和重视上。
|
|
@ -0,0 +1,99 @@
|
|||
## 17.2 软件质量保障概述
|
||||
|
||||
软件质量保障(Software Quality Assurance,简称SQA)是一个比软件测试范围要更大、更泛的话题。从项目管理的视角上看,质量保障是确保产品可以达到其客户或者雇主设定的交付标准所制定的流程。具体到软件开发,软件质量保障是一系列活动,包括规划、定义、控制、保障和改进那些影响产品质量的过程和相关活动,覆盖了软件产品开发的整个生命周期,从需求获取、软件设计和编码,到测试和维护。一般认为测试是质量保障的一部分。
|
||||
|
||||
### 17.2.1 软件质量保障 V.S. 软件质量控制
|
||||
|
||||
为了进一步说明软件质量保障(Quality Assurance)的含义,我们把它和另一个经常被提及的概念,软件质量控制(Quality Control),进行一轮对比:
|
||||
|
||||
- 软件质量保证是一种预防性活动,重在防止问题的发生,通过制定和实施质量计划、设置标准和流程、培训团队成员等方法提升软件开发过程的质量。它的目标是保证软件开发过程符合预期的质量标准,最大程度降低缺陷和问题的风险。
|
||||
- 软件质量控制则更多是检测性活动,侧重于评估软件的质量并找出并修复其中的缺陷。它主要通过执行测试、代码审查、缺陷管理等手段来保证软件质量的达标。软件质量控制的目标是在软件交付前检测和修复软件中的缺陷,并保证软件满足预期的质量标准。
|
||||
|
||||
简单来说,软件质量保证着眼于预防问题发生,通过规范和改进过程来达成质量标准;软件质量控制则是在产品层面,通过检测和验证以发现和修复问题。敏捷软件开发中的软件质量内建"Built-in Quality",强调从一开始就把质量纳入到产品的设计和开发过程中,更接近于质量保障的范畴。
|
||||
|
||||
<img src="img/Slide4.SVG"/>
|
||||
|
||||
换言之,软件质量保障的“终极目标”是使产品达到预期标准,并通过流程实现“长治久安”,而不仅仅是避免、发现或者修复缺陷。这个定位和软件测试以及软件质量控制都不同。可以认为,SQA追求的是扁鹊长兄的“于病视神,未有形而除之”。
|
||||
|
||||
### 17.2.2 软件质量的内涵
|
||||
|
||||
那么,质量保障这个“大问题”该如何分解到开发实践当中?首先,我们要保障“质量”,那就要明确软件的“质量”到底指的什么。在本书的最初我们提到过:
|
||||
|
||||
$$
|
||||
软件 = 程序 + 软件工程 \tag{17.1}
|
||||
$$
|
||||
|
||||
这就意味着,一个优秀的软件不仅仅是由其程序代码决定的,更在于软件开发和管理过程的质量和有效性。那么“代入”质量,我们可以得出如下的进一步公式:
|
||||
|
||||
$$
|
||||
软件的质量 = 程序的质量 + 软件工程的质量 \tag{17.2}
|
||||
$$
|
||||
|
||||
这就展开了“软件的质量”的含义。这里,软件质量被分解为“程序的质量”和“软件工程的质量”。这意味着,优秀的代码(程序质量)和优秀的开发、测试和维护流程(软件工程质量)是确保软件质量的关键。
|
||||
|
||||
<img src="img/Slide5.SVG"/>
|
||||
|
||||
笔者认为,放到更大的时间尺度上,质量最终要落到“人”上,和团队的质量意识、文化密不可分,在实际的操作上,这个文化会体现在团队的流程设计的完善度、QA团队的话语权等等,而并非虚无缥缈的政治口号。因此,这里可以加一个“buff”:
|
||||
|
||||
$$
|
||||
长期的软件质量 = (程序的质量 + 软件工程的质量) * 团队的质量文化系数 \tag{17.3}
|
||||
$$
|
||||
|
||||
优秀的团队质量文化,如开放的沟通、积极的学习、持续的改进等,能够有效地提升软件的质量。反之,如果团队的质量文化弱,那么即使程序的质量和软件工程的质量都很高,如果出现流程混乱、关注点缺失、优先级错配,就很难说质量可以“长治久安”。
|
||||
|
||||
上面的内容讨论中,我们尝试联系前面的公式,拆解了软件质量的概念。在我国的软件工程向拼质量的相关标准中,就分四个层面提出了过程质量、内部质量、外部质量和使用质量,来展开软件质量的内涵:
|
||||
|
||||
- **过程质量**:过程质量衡量软件的研发过程对于质量的保证程度,较好的过程质量意味着软件的研发过程是按照比较科学的方式方法进行,也就是我们上面说的“长治久安”。
|
||||
- **内部质量**:内部质量是指软件研发过程中软件的质量,在这个过程中会产生的需求文档、概要设计、详细设计等文档和编码实现,这些共同影响内部质量。内部质量是由开发来把控。
|
||||
- **外部质量**:外部质量指地是软件开发完成后,整体运行时暴露出来质量特性,外部质量的界定是由系统测试的来对软件进行质量评判的工作。
|
||||
- **使用质量**:当软件交付用户后,由用户在使用时感受及目标的符合程度,简单来说就是用户说你的软件好不好,这就是使用质量。
|
||||
|
||||
前面的过程、内部、外部质量都可以由公司的内部人员来进行评估;而使用质量一般是用户或企业客户说了算。以上四个维度的质量和我们上面说的质量拆解法的异曲同工之处在于,两者都强调了质量既是一个“结果”,也是一个“过程”,因此需要体系化、标准化的手段来保障。
|
||||
|
||||
### 17.2.3 常见的软件质量标准
|
||||
|
||||
软件质量标准的定义是质量保障的起始点,对于软件产品,我们可以参考ISO/IEC 25010 系统和软件工程质量评估模型,来构建一个初步的质量标准框架:
|
||||
|
||||
<img src="img/Slide6.SVG"/>
|
||||
|
||||
我们选取一些比较常用的核心指标,并把它们按照不同的开发阶段来进行梳理解读如下:
|
||||
|
||||
- 开发期代码质量:
|
||||
- 易理解性(Understandability):指设计被开发人员理解的难易程度。
|
||||
- 可扩展性(Flexibility):软件因适应新需求或需求变化而增加新功能的能力,也称为灵活性。
|
||||
- 可测试性(Testability):对软件测试以证明其满足需求规范的难易程度。
|
||||
- 可重用性(Resuability):指重用软件系统或某一部分的难易程度。
|
||||
- 可维护性(Maintainability):当需要修改缺陷、增加功能、提高质量属性时,定位修改点并实施修改的难易程度;
|
||||
- 可移植性(Portability):将软件系统从一个运行环境转移到另一个不同的运行环境的难易程度。
|
||||
- 运行期产品质量需求:
|
||||
- 性能(Performance):性能是指软件系统及时提供相应服务的能力,包括时间(Time Behavior,一般和速率相关,软件执行功能时的响应、处理时间和吞吐率
|
||||
)、资源利用(Resource Utilization,软件执行功能时所使用的资源数量和类型)和容量消耗(Capacity,产品或系统参数最大限度满足需求的程度,和服务的持续高速性相关)三方面的要求。
|
||||
- 安全性(Security):指软件系统同时兼顾向合法用户提供服务,以及阻止非授权使用的能力。
|
||||
- 易用性(Usability):指软件系统易于被使用的程度。
|
||||
- 可伸缩性(Scalability):指当用户数和数据量增加时,软件系统维持高服务质量的能力。例如,通过增加服务器来提高能力。
|
||||
- 互操作性(Interoperability):指本软件系统与其他系统交换数据和相互调用服务的难易程度。
|
||||
- 可靠性(Reliability):软件系统在一定的时间内无故障运行的能力。
|
||||
- 可观测性(Observability):指能够通过检查系统或应用的输出、日志和性能指标来监控、测量和理解系统或应用的状态。。
|
||||
- 持续可用性(Availability):指系统长时间无故障运行的能力,与可靠性相关联,常将其纳入可靠性中。
|
||||
- 鲁棒性(Robustness,差错防御):是指软件系统在一些非正常情况(如用户进行了非法操作、相关的软硬件系统发生了故障等)下仍能够正常运行的能力,也称健壮性或容错性。
|
||||
|
||||
<img src="img/Slide8.SVG"/>
|
||||
|
||||
同时,开发期的质量体现和运行期的质量需求是可以相互联系在一起的。比如:
|
||||
|
||||
- 易理解性和可维护性可以直接影响产品的性能和可靠性。如果代码的设计和架构不易理解,那么开发人员可能会在修改和优化代码时遇到困难,从而可能会导致性能下降、出现新的错误或增加错误修复的时间;
|
||||
- 开发期的可测试性也可以直接影响运行期的可靠性和鲁棒性。只有当软件的所有部分都可以被有效地测试时,才能保证在各种环境和条件下都能正常工作。较低的可测试性可能导致整体测试覆盖率无法突破瓶颈,可能在面对非常规情况或者用户非预期的操作时,出现无法预测的错误,影响软件鲁棒性(Robustness);
|
||||
- 开发期的可扩展性和可移植性也对运行期的可伸缩性和互操作性有着重要的影响,云环境下,高可扩展性更可能应对大规模的用户和数据增长。可移植性则保证了软件可以在不同的环境或平台上运行,使得与其他系统的交互成为可能;
|
||||
- 开发期的可重用性可以影响到运行期的各个方面。通过重用经过严格测试和验证的代码,可以提高开发效率,同时减少出错的可能性,提高软件可靠性和安全性。
|
||||
|
||||
更多的标准之间的相互关联性、竞争性,可见下表:
|
||||
|
||||
<img src="img/Slide7.SVG"/>
|
||||
|
||||
### 17.2.4 软件质量保障的重要性
|
||||
|
||||
亚里士多德说过:“我们反复做的事情塑造了我们,因此卓越不是一种行为,而是一种习惯。”质量和卓越一样,不是可以简单完成的任务或清单,而是需要在开发和服务生命周期中持续、习惯性的投入。在微软,质量保障被认为是"卓越软件工程"(Engineering Excellence,简称EE)的关键部分,并提出质量开发生命周期“Quality Development Lifecycle”,将对质量的重视和实践贯穿于定义、设计、开发、运维和学习精进的周期中。对软件质量的重视和“以用户为中心”的理念密不可分,而不是一句空谈。
|
||||
|
||||
在上一小节的故事中,我们能非常深刻的感受到开发团队对质量的重视:项目经理虽然急切想要发版,使得合作伙伴能尽快试用上新功能,但这不能以牺牲软件质量为代价;生产环境有严格的软件可靠性指标,即使是只有千分之一的概率偶现问题,研发经理也坚持修复后在发布;QA工程师有很高的一票否决权,这源于对软件质量情况的准确把控。开发团队有能力搞清楚自己开发的软件质量的“真相”是非常重要的,这是质量内建和质量保障的立足点。
|
||||
|
||||
良好的质量保障体系可以提高开发效率,让开发中的逻辑问题尽早暴露,降低修复成本;高质量的软件可以提升用户满意度,和客户建立信任。这些都是软件繁荣发展的基石。下一小节,我们将探讨应用相关技术构建质量保障体系,并展望未来。
|
|
@ -0,0 +1,127 @@
|
|||
## 17.3 质量保障体系的构建
|
||||
|
||||
结合上一小节对于质量内涵外延的探讨,软件研发团队建立有效的软件质量保障(SQA)体系一般涉及如下几个要点:
|
||||
|
||||
1. **理解需求**:首先,质量保障团队要充分理解要开发的软件产品和服务所满足的外部需求,明白目标用户期待什么、关注什么。
|
||||
2. **定义质量指标**:结合产品的需求和用户场景,设定符合软件产品实际情况的质量目标,这可以参考我们上一节提到的一些核心指标:可靠性、性能效率、可用性、安全性等。
|
||||
3. **建立标准和过程**:这是保障质量的关键一步。我们需要为团队制定一套清晰的、可执行的开发和测试标准,从行为和范式上定义什么是“正确的”,什么是有益于软件质量的。
|
||||
4. **实施质量保证活动**:根据设定的标准和流程来将流程渗透到代码审查、自动化测试、性能测试的具体过程中,尽可能利用内部DevOps系统平台将他们以自动化的方式实施。
|
||||
6. **培训和教育**:让你的团队理解和重视质量保证的重要性,提供必要的培训,使他们能够执行质量保证的任务。
|
||||
5. **持续评估、监控和改进**:通过收集和分析各类数据、用户和团队反馈来监控软件质量,并根据结果对研发流程进行持续改进。
|
||||
|
||||
笔者认为,一个开发团队的QA体系并不是“设计”出来的,也不是大家一起“头脑风暴”出来的。体系的建立需要团队在合作、演进乃至犯错的过程中总结提升进行。软件的“质量真相”可能是一个很好的团队讨论议题。团队成员坐在一起,面对质量仪表和进度看板,审视自己团队产品的状况,从用户和验收的视角讲出软件质量的真实情况,形成有效结论,并设立一些仪式感的小程序来奖励讲出质量真相和提出好建议的同学。也可以从以下数据出发,围绕一些关键的质量能效指标来展开话题,比如:软件开发完成(Code Complete)之后Bug的数量、修复Bug所用的时间、用户的好评差评,以及软件能运行多久,平均初次错误时间(Mean Time To Failure)平均无故障时间(Mean Time Between Failure),这些都是重要的质效参考。
|
||||
|
||||
如果团队在这些内容的探讨上没有透明度、开放度,领导层也不重视,那么产品很容易进入自嗨、皇帝的新衣的困局中。换言之,我们需要质量真相的讲述者,“We need the quality truth teller”。本章开篇的故事中,如果没有小陈和木头追踪OOM的情况,展示真相,可能这个问题会被忽视;而上线仪表盘在bug优先级提升后,显示出警戒的红色,也有利于将这一情况广播出来,闻者足戒。
|
||||
|
||||
### 17.3.1 CMM能力成熟度模型与成熟度晋级要点
|
||||
|
||||
以上我们简要从要点和文化层面探讨了质量保障体系,更多集中在“势”和“道”的层面。然而,具体的体系还需要能够实实在在地驱动团队行动起来的流程、工具和数据。
|
||||
|
||||
那么要落实到“术”和“器”的层面,我们还需要“法”,CMM能力成熟度模型就可以作为一个重要的参考,它的成熟度层级的定义也符合我们刚刚讲到的“演进”的概念。CMM(Capability Maturity Model,能力成熟度模型)是一个过程级别改进的训练和评估模型,旨在优化业务流程并达到更高效、更高质量的结果。这个模型最初是为软件开发工程设计的,但现在已经扩展到多种领域,包括产品开发和服务提供。CMMI(Capacity Maturity Model Integration,能力成熟度模型集成)是指将该模型应用到项目中的集成情况,是一套理论体系,包括模型、实施指导、工具系统、培训认证以及评定方法。由于CMMI在网络上结构化的公开资料非常多,我们将不会赘述其概念,而是基于该模型体系展开其对于软件质量保障的参考意义。
|
||||
|
||||
如下图,CMMI将产品开发业务流程为五个成熟度级别,从1(初始级别)到5(优化级别):
|
||||
|
||||
<img src="img/Slide10.SVG"/>
|
||||
|
||||
1. **初始级 (CMMI 1级)**
|
||||
- **状态**: 新成立的软件公司默认在这一级别,过程无序、混乱。
|
||||
- **特征**: 依赖个体能力和“英雄主义”来救场。项目成功通常依赖个别杰出经理和有经验的软件团队。CMMI没有针对1级的评估,官方默认所有未进行CMMI评估的企业,至少具备CMMI 1级水平。
|
||||
- **问题**: 进度、预算、功能性和产品质量都是不可预测的。
|
||||
|
||||
2. **可管理级 (CMMI 2级)**
|
||||
- **状态**: 在部门或项目组范围内有基础的管理体系。
|
||||
- **特征**: 管理和控制已初步设置。项目有方针和规程,借鉴以往的成功实践。这样的的管理会快速帮助项目组或者部门提升开发工作的效率与质量,但是并没有在整个组织范围内推广开来。
|
||||
- **问题**: 主要集中在项目级别,而不是组织级别。
|
||||
|
||||
3. **已定义级 (CMMI 3级)**
|
||||
- **状态**: 组织范围内有统一、标准的管理制度。
|
||||
- **特征**: 整个组织的软件过程已文档化并标准化,有专职人员进行监督。CMMI3级是重要的承上启下的一环,因为组织范围内的统一管理,不仅有助于提高软件产品与服务的效能与质量,其稳定的过程可以为进一步的量化管理提供标准的分析数据,也帮助组织逐渐形成了管理的文化。
|
||||
- **优势**: 有助于进一步的量化管理和文化建设。
|
||||
|
||||
4. **量化管理级 (CMMI 4级)**
|
||||
- **状态**: 在稳定的基础上进行量化管理。
|
||||
- **特征**: 收集数据,建立基线与模型,实现过程和产品质量的定量预测。CMMI4级之前,主要是定性的方式进行管理;而从4级开始,组织在标准而稳定的过程下,收集软件开发过程中的数据,建立基线与模型,开启企业的量化管理之门。量化管理不仅可以将隐形的软件开发过程,通过数据显性的表达出来,还能基于企业的历史经验,在统计学方法指导下,预测项目的进展情况。
|
||||
- **优势**: 项目进展和质量可预测,有更多的度量指标。
|
||||
|
||||
5. **持续优化级 (CMMI 5级)**
|
||||
- **状态**: 组织内部形成了持续优化的文化。
|
||||
- **特征**: 不断寻求新技术和新方法,致力于绩效指标的量化提升。该级别最重要的是企业内部形成了自觉的持续优化文化。组织及其成员会不断寻求新技术、新方法,追求管理上可量化的绩效指标提升。这种文化,还为企业的管理变革和转型奠定了坚实的基础,帮助企业在取得阶段性胜利之后,跨越平台期,迈向下一个改进循坏的开始,促成进一步的成长。
|
||||
- **优势**: 为企业的持续成长和转型提供了坚实的基础。
|
||||
|
||||
<img src="img/Slide11.SVG"/>
|
||||
|
||||
最后,我们结合本章软件质量的主题,总结出一个组织或研发团队在CMMI标准下的成熟度晋级要点包括:
|
||||
|
||||
- **从1级到2级**: 主要关注项目管理的过程改进。
|
||||
- 这个过程中组织的主要注意力应该在项目和具体的过程质量上,组织应该推动制定项目级质量保障计划,明确基础的质量指标和各个发布节点的检查清单;和开发团队协定代码编写的规范和约定,完善代码评审流程。
|
||||
- **从2级到3级**: 主要关注组织级的过程全面改进。
|
||||
- 该层面的注意点在于审视组织架构、权责定义和划分,如果必要的话要进行组织重构;完善软件质量的培训体系,鼓励大家重视质量;对于出现的线上质量问题,大家开诚布公地共同反思(切忌,这类会议一定要要建立坦诚和鼓励包容的氛围,不要搞成甩锅大会),并让大家意识到软件质量问题的严重性,并真正能从错误中学习成长,不断变强。
|
||||
- **从3级到4级**: 着重于过程定量管理的改进。
|
||||
- 这时团队在质量保障的意识层面是上下一心的,那么用数据和量化手段去进一步推进科学管理就比较顺理成章,团队就要关注质量数据收集和分析,从用户和外部要求出发,立足产品目前的实际质量情况,建立质量基线和模型,然后将数据用可视化的手段呈现出来,进而再实现对指标的持续监控。
|
||||
- **从4级到5级**: 聚焦于技术革新和过程优化的改进。
|
||||
- 最后,团队可以关注不断利用新的技术创新手段(如智能异常模式识别、数据预测系统、智能诊断分析),持续改进,让整个质量保障体系更加自动化和智能化;也可以考虑一部分核心指标形成KPI或者OKR,和团队的绩效挂钩,更好的激励团队在质量上精进。
|
||||
|
||||
<img src="img/Slide12.SVG"/>
|
||||
|
||||
### 17.3.2 常用技术手段
|
||||
|
||||
在项目开发和实施的“术”的层面,软件质量保障的技术手段是比较多元的。这里笔者依据从代码编写、编译构建到上线的先后时间顺序,列出了一些常用的、和研发过程直接相关的技术手段,不再分别展开描述,仅作参考:
|
||||
|
||||
1. **集成开发环境的协同编程工具和助手**
|
||||
|
||||
由于我们谈的是“术”的层面,就不再考虑设计层面的质量考量,那么,编写代码就往往会成为产品质量“形成”的起始点,集成开发环境,也就是我们常说的IDE,就非常重要,他们往往提供了内置的检测和代码生成(比如Visual Studio的IntelliSense,IntelliJ的Code Inspection等,还有最新的GitHub Copilot X在Visual Studio Code中提供的各种插件:Copilot Chat,Copilot Lab等),这些工具和助手帮助工程师们做了很多工作,包括程序代码的编写、调试和版本控制等。这些技术不仅关乎效率,也关乎“第一手”代码的质量。
|
||||
|
||||
在版本控制层面,笔者早年开发还和团队实践过利用Git Hook功能在代码提交、推送等时间节点上嵌入质量脚本,进行质量检查的方案,现在Jira、Jenkins等平台已经很成熟,貌似很少有团队还在利用Git Hook做质量卫士(Quality Gatekeeper)了。
|
||||
|
||||
2. **静态代码分析和扫描**
|
||||
|
||||
这类技术一般在不实际运行代码的情况下,自动地检查和分析源代码或构建产物中的机器码以查找可能存在的逻辑漏洞或编码不当之处。在持续集成流程中加入代码分析工具,如SonarQube、Checkmarx、CheckStyle、Fortify、lint、errorprone等,自动标记出可能的代码问题和安全隐患。目前这个技术下的各类成熟和开源方案比较多,可以比较方便的集成到各类持续集成系统中。
|
||||
|
||||
笔者认为这类方案中非常值得借鉴和学习的是其中对于代码常见错误或违规(Violation)的定义,这些定义是大量编码经验总结和分类之后汇总成的宝藏“错题本”,定义了违规和错误的模式、危害和修复建议,而且往往有非常详尽的说明和文档,从中可以学到很多有价值的编码知识,推荐大家去涉猎。
|
||||
|
||||
3. **代码评审**
|
||||
|
||||
即Code Review,现在大部分团队都用上了Gerrit、GitHub、GitLab这类支持Code review workflow的平台,来让人工代码检查合理地接入到研发流程当中,大家可以在Pull request里直接针对相关的代码上下文反馈、建议、讨论和甚至聊天(也可以吐槽和互喷)。
|
||||
|
||||
这项技术也很成熟了,开发实战中的核心要点在于,我们应该如何定义某个代码改动谁来评审,多少人来评审。这些约定往往体现了团队的质量文化,以及反映了开发团队人员的权责、资深情况。相关的技术实施一般通过代码托管平台的权责规则定义来实现,例如GitHub Code Owners、Azure DevOps Branch Policy这样的功能模块。笔者所在的团队以前为了鼓励大家多多评审,还尝试过利用平台所提供的API,把团队所有开发的评审条数、PR贡献数做成英雄榜展示给大家,十分有趣。
|
||||
|
||||
4. **软件质量仪表盘和异常监控**
|
||||
|
||||
质量标准仪表盘,或者叫“质量数据大屏”,并不是一项单纯的数据可视化的技术,它是团队建立质量标准、数据埋点和统计量化、可视化仪表设计、基线认同设定等工作搞定后的最终成果呈现,一般意味着这个团队已经有较高的成熟度。
|
||||
|
||||
如果一个质量仪表盘视图能量化地呈现团队开发的软件产品的质量真相,从而帮助团队作出可靠的定性判断,那么它对于这个产品和团队的价值是不可估量的。产品质量情况需要透明度,一个缺乏用户质量感知的团队是无法生存下去的。
|
||||
|
||||
Azure DevOps平台就支持构建Dashboards功能,可以较好地展现当前团队关键bug数量和优先级等核心信息,再结合一些线上数据(如宕机率、应用卸载率、差评率)监控手段,就足以驱动团队向持续优化的方向演进。对于新成立的团队,也可以尝试使用Grafana和Prometheus等开源工具进行实时性能和错误监控。
|
||||
|
||||
以上几个技术无法涵盖整个软件质量保障体系下的技术生态,近年来可观测性和ELK stack的概念的火热也说明了该领域的重要性。在微软,各个团队采用不同的手段保证质量,有的项目没有专门的QA,是PM/Dev兼任,这种组织主导下的质量保障更多融入于生产过程中,更灵活;而有QA的组织会有更明确的分工、职责和程序,可以清楚地看到有两股驱动力在打磨产品。但不管是哪种模式,各个团队都会采用静态代码分析一类的自动化手段提高效率,采用威胁建模(Threat Modeling)来进行风险暴露和评估,使用扫描工具来检查关键信息和秘钥泄漏,由专门的产品安全团队检查代码的安全性,进行全面的安全性检查。
|
||||
|
||||
### 17.3.3 未来展望
|
||||
|
||||
进一步讲,一个理想的质量保障体系,可能涉及到软件开发、团队合作的诸多方面,以下是一段“蓝图”的描述:
|
||||
|
||||
假设你是一位全栈产品经理,专精用户体验,熟知我们的客户、系统,且能定义关键指标。你理解应用与服务间的互动与协定,使用自助工具获得所需答案。昨天,你刚和团队一同庆祝达到5000万月活跃用户的重要里程碑,与客户公司高层共享喜悦。今晨,你打开我们的服务质量(Quality of Services)仪表板,看到:
|
||||
|
||||
- 应用和平台关键服务水平目标(SLOs,Service Level Objectives)的视图。理想体验的用户端设备比例创纪录的达到了99.5%。
|
||||
- 上次重大缺陷进入生产环境已经54天。你记得参加的缺陷原因分析,以及改善异常检测的解决方案。
|
||||
- 绿色标识代表成功的自动化测试运行及覆盖范围,包括单元、组件、集成、压力、UI和长期测试。
|
||||
- 事件部分显示,服务在昨晚的Beta环境中,根据端到端的性能SLOs,自动回滚了部署。这个构建需要复查。
|
||||
- 发布部分证实已发布的功能和应用版本满足所有发布条件,包括可靠性、性能、检查表和记分卡。顶部显示一些“待定”功能,直到满足质量标准,持续集成系统中明确了下一步及负责人。
|
||||
- 客户反馈问题部分显示,有新的质量问题在内部被报告。你点击查看受影响的用户总数、各个用户的“服务稳定系数”,自动分析显示消息节点出现问题。用户的“服务稳定系数”低于预期目标时,会自动生成包含诊断数据的错误报告。
|
||||
- 客户反馈部分显示,最大的10个请求都是新功能需求。其中一条关于与外部游戏厂商集成的想法引人注目。总体情感得分和词云显示用户喜爱最新的应用版本。
|
||||
- 商业指标部分显示了基于参与度、使用情况、可靠性、性能和应用评级的最新预测。联系质量洞察与商业指标需要大量工作,但现在已经行之有效。
|
||||
|
||||
在这个“蓝图”中,我们可以看到一些现在已经广泛应用的测试工程化、持续集成和持续交付、代码审查和静态代码分析、数据驱动的质量保障、用户为中心的反馈处理系统和自动缺陷分析等质量保障技术和流程。
|
||||
|
||||
在未来,AI和大语言模型一定会大举赋能软件质量保障,推动质量智能化时代的到来,越来越多的团队达到 CMM “持续优化”的成熟度的成本降低、可能性不断增加:
|
||||
|
||||
1. **软件质量保障智能化**: 随着AI和机器学习技术的发展,我们预期它们将在软件质量保障中扮演更重要的角色。例如,AI可以用于预测哪部分代码最可能出现缺陷,或者用于自动化地生成测试用例。不限于以下方面:
|
||||
- 智能代码生成。
|
||||
- 代码质量智能分析,代码质量“格式刷”。
|
||||
- 智能代码评审助手将直接参与到代码评审环节中,辅助对代码风格、规范化、潜在bug提出针对性建议。
|
||||
- 工程化测试用例智能生成方案。
|
||||
- 代码逻辑可视化和模块链路分析,诊断建议。
|
||||
- 智能日志分析、监控预警。
|
||||
2. **基于云的质量保障**: 随着云计算的普及,基于云的质量保障服务(如云测试、云构建等)将得到更广泛的应用。
|
||||
3. **更大规模的自动化和集成**: 随着DevOps和自动化工具的进步,我们预期在质量保障流程中的自动化和集成将进一步扩大,可以处理更大的代码模块的设计、重构,本根据团队的风格、约定进行定制化支持。
|
||||
|
||||
最终,在AIOps、LLM等智能技术的赋能下,软件的质量保障是否可能在特定领域可以实现一站式服务,我们只需要写代码,系统能够自动构建、分析、扫码、测试问题,自动出具综合质量报告,并提供修复建议?就像前一章小陈老张在食堂聊的“无人办公室”一样工作?这听起来很不可思议,但似乎在越来越近。
|
|
@ -0,0 +1,16 @@
|
|||
|
||||
### 思考与练习
|
||||
|
||||
1. 本章开篇发版作战室故事中的团队讨论中体现了哪些软件质量保证的手段和流程?你认为这个团队属于CMMI的哪个成熟度等级?
|
||||
2. 你会如何说服团队领导真正重视软件质量并愿意为之投资人力物力资源?
|
||||
3. 假设我们团队的所有研发工程师都能做到写代码没有Bug和任何实现缺陷,是不是我们就不需要软件质量保障了?
|
||||
4. 服务端质量体系和客户端软件质量体系在构建上是否有很大差异?他们之间的联系是什么?
|
||||
|
||||
### 参考资料
|
||||
|
||||
[1] 《构建之法》,邹欣,人民邮电出版社
|
||||
[2] CMMI institude, https://cmmiinstitute.com/
|
||||
[3] 微软开源智能云测试平台 Hydra Lab,GitHub,https://github.com/microsoft/HydraLab
|
||||
[4] 系统与软件质量模型,全国标准信息公共服务平台,https://std.samr.gov.cn/gb/search/gbDetailed?id=71F772D81641D3A7E05397BE0A0AB82A
|
||||
[5] System and software quality models,ISO,https://www.iso.org/standard/35733.html
|
||||
[6] 打造更聪明的猴子:开源云测框架 Hydra Lab 的智能化测试实战,InfoQ,https://www.infoq.cn/article/YaUjY3klLG6iT7cWvPAy
|
После Ширина: | Высота: | Размер: 81 KiB |
После Ширина: | Высота: | Размер: 58 KiB |
После Ширина: | Высота: | Размер: 66 KiB |
После Ширина: | Высота: | Размер: 38 KiB |
После Ширина: | Высота: | Размер: 68 KiB |
После Ширина: | Высота: | Размер: 41 KiB |
После Ширина: | Высота: | Размер: 71 KiB |
После Ширина: | Высота: | Размер: 117 KiB |
После Ширина: | Высота: | Размер: 99 KiB |
После Ширина: | Высота: | Размер: 77 KiB |
После Ширина: | Высота: | Размер: 80 KiB |
После Ширина: | Высота: | Размер: 86 KiB |