This commit is contained in:
louzefeng
2024-07-11 05:50:32 +00:00
parent bf99793fd0
commit d3828a7aee
6071 changed files with 0 additions and 0 deletions

View File

@@ -0,0 +1,146 @@
<audio id="audio" title="测试专栏特别放送 | 浅谈全链路压测" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/f4/69/f4166e598827912a2c0a3181b1301369.mp3"></audio>
你好,我是茹炳晟。今天我和你分享的主题是:浅谈全链路压测。
时光飞逝从专栏上线至今我已经和你分享了52篇文章和7篇答疑文章和你分享了软件测试中的各个主题希望已经帮你构建了一幅软件测试的知识全景图。
在前面的“性能测试”系列文章中我以LoadRunner为例和你分享了传统企业在实际开展企业级性能测试的实践。并且在第32篇文章[《无实例无真相基于LoadRunner实现企业级服务器端性能测试的实践](https://time.geekbang.org/column/article/18120)中,我和你分享了这么安排的原因,并承诺在专栏结束前,通过一篇“加餐”文章,和你分享开展全链路压测的难点,以及应对方案。
现在,就是我践行承诺的时间了。
我也不太清楚,你现在具备多少全链路压测的知识。所以,我会先和你分享一些全链路压测的理论知识,然后再分享具体的难点以及解决思路,帮你加深理解,希望可以让你听得明白、学得会、用得着。
## 什么是全链路压测?
全链路压测,是基于真实的生产环境来模拟海量的并发用户请求和数据,对整个业务链路进行压力测试,试图找到所有潜在性能瓶颈点并持续优化的实践。
目前,一线互联网公司的大型电商平台都会不定期地开展全链路压测,比如淘宝、京东、饿了么和美团这些企业,基本都已经有了自己的全链路压测方案和平台。
其中最为典型的要数淘宝的双11活动了。每年到了11月11日的零点淘宝的整个系统都会面临极大的流量冲击如果事先没有经过充分的测试和容量预估很可能会在流量爆发时瘫痪。
记得在早些年的淘宝双11大促中就出现了不同程度的网站故障严重影响了用户体验所以从2013年开始淘宝开始实施全面的全链路压测。由于在真正的双11到来前淘宝内部已经模拟了比双11流量还要高的负载并且逐个解决了已经发现的问题因此真正双11到来的时候就不会出现严重的问题了。
因此为了防止此类事故淘宝会在每在双11之前就对系统的稳定性以及负载承受能力进行必要的测试和评估。
当然,**全链路压测的应用场景,不仅仅包括验证系统在峰值期间的稳定性,还会包含新系统上线后的性能瓶颈定位以及站点容量的精准规划。**
比如,由于某些业务模块的操作负载会集中到几个最核心的组件上,那么通过全链路压测的模拟,我们就能快速识别出哪些模块的负载过大,哪些模块的负载偏小。这样我们在对系统进行扩容时,就可以把资源更多地给到那些承受大负载的模块,而那些承受负载偏小的模块就可以进行适当的收缩来让出更多的可用资源。这,就是精准的容量规划。
## 单系统的独立压测
早先的时候,压测并不是针对业务的全链路来开展的,而是采用了“各个击破”的原则,即对生产环境中的单机或者单系统进行独立的压测。这时,压测主要是通过模拟单一系统的海量并发请求来实现的。而模拟海量请求主要有两种实现方式:
- 一种是,根据设计的压力来直接模拟大量的并发调用;
- 另一种是,先获取线上真实的流量请求,然后经过数据清洗后,再回放模拟大量的并发调用。
不管采用的是哪种方式,都会涉及流量模拟、数据准备、数据隔离等操作。除此之外,单系统的独立压测局限性也非常明显。
这里,我把单系统独立压测的局限性,归纳为了以下几点:
- 单系统压测的时候,会假设其依赖的所有系统能力都是无限的,而实际情况一定不是这样,这就造成了单系统压测的数据普遍比较乐观的情况;
- 在大压力环境下,各系统间的相互调用会成为系统瓶颈,但这在单系统压测的时候根本无法体现;
- 大压力环境下,各系统还会出现抢占系统资源(比如网络带宽、文件句柄)的情况,这种资源抢占必然会引入性能问题,但是这类问题在单系统压测过程中也无法体现出来;
- 由于是单系统测试,所以通常都只会先选择最核心的系统来测试,这就意味着其他的非核心系统会被忽略,而在实际项目中,这些非核心系统也很有可能会造成性能瓶颈。
因此,为了解决单系统独立压测的一系列问题,业界就衍生出了全链路压测。全链路压测会把整个系统看作一个整体,然后在真实的生产环境上尽可能真实地去模拟业务的海量并发操作,以此来衡量系统的实际承载能力,或者找出系统可能的瓶颈点并给出相应的解决方案。
目前来看,全链路压测需要解决的技术难点有很多,这里我会和你讨论其中最重要的四个点:
<li>
海量并发请求的发起;
</li>
<li>
全链路压测流量的隔离;
</li>
<li>
实际业务负载的模拟;
</li>
<li>
测试完成后的数据清理。
</li>
## 海量并发请求的发起
由于全链路压测需要发起的海量并发通常会超过每秒1000万次以上请求的压力量级所以传统的性能测试工具LoadRunner已经很难满足要求了原因有二
- 一来LoadRunner按并发用户数收费这就使得采用LoadRunner进行互联网的全链路压测的费用会异常高
- 二来LoadRunner本身也很难支持千万级乃至亿级的海量并发。
所以业界基本都是采用免费的JMeter来完成全链路压测这也是JMeter近几年被互联网企业广泛使用的原因。
但是即便有了JMeter我们在开展全链路压测时也会有很多问题需要解决。其中最主要的问题包括以下三个
<li>
<p>**虽然采用了分布式的JMeter方案并发数量也会存在上限**比如面对亿级的海量并发时主要原因是分布式的JMeter方案中Master节点会成为整个压测发起的瓶颈。<br>
为了解决这个难题很多公司并不会直接采用分布式JMeter架构来完成海量并发而是会使用Jenkins Job单独调用JMeter节点来控制和发起测试压力。这样就避免了Master节点引发的瓶颈问题。而且由于各个JMeter是完全独立的所以只要Jenkins Job足够多并且网络带宽不会成为瓶颈的情况下就能发起足够大的并发。</p>
</li>
<li>
<p>**测试脚本、测试数据和测试结果在分布式JMeter环境中的分发难题**。如果直接采用分布式的JMeter方案测试脚本需要通过JMeter的Master节点来分发测试数据文件则要用户自行上传至每套虚拟机同时测试结果还要通过JMeter的Slave节点回传至Master节点。<br>
所以更好的做法是基于JMeter来搭建一个压测框架诸如脚本分发、数据分发以及结果回传等工作都由压测框架完成。这也是目前绝大多数大型互联网企业的做法。比如饿了么就采用这种方式搭建了压测平台并且取得了很好的效果。</p>
</li>
<li>
**流量发起的地域要求**。全链路压测流量的发起很多时候是有地理位置要求的比如30%的压力负载来自上海、30%的压力负载来自北京等这就要求我们在多个城市的数据中心都搭建JMeter Slave以便可以发起来自多个地域的组合流量。
</li>
## 全链路压测流量和数据的隔离
因为全链路压测是在实际的生产环境中执行的,所以测试产生的数据与真实的用户数据必须进行有效隔离,以防止压测的流量和数据污染、干扰生产环境的情况。比如,不能将压测数据记录到统计分析报表里;再比如,压测完成后可以方便地清洗掉压测产生的数据。
为了达到这个目的,**我们就需要对压测流量进行特殊的数据标记,以区别于真实的流量和数据**。这就要求各个链路上的系统,都能传递和处理这种特殊的数据标记,同时写入数据库中的数据也必须带有这种类型的标记以便区分数据,或者直接采用专门的影子数据库来存储压测的数据。
可以看出,为了实现压测产生的和真实的流量和数据隔离,我们就需要对各个业务模块和中间件进行特殊的改造和扩展。而这个工作量相当大,而且牵涉的范围也非常广,也就进一步增加了实施全链路压测的难度。
而且通常来讲,首次全链路压测的准备周期会需要半年以上的时间,这其中最大的工作量在于对现有业务系统和中间件的改造,来实现压测流量和数据的隔离。所以,在实际的工程项目中,如果全链路压测不是由高层领导直接牵头推动的话,很难推进。
另外,在对各个业务模块和中间件添加特殊标记的改造过程中,我们会尽可能少地改动业务模块,而是更倾向于通过中间件来尽可能多地完成特殊数据标记的处理和传递。
## 实际业务负载的模拟
一直以来,如何尽可能准确地模拟业务系统的负载,都是设计全链路压测时的难题。这里的难点主要体现在两个方面:首先,要估算负载的总体量级;其次,需要详细了解总负载中各个操作的占比情况以及执行频次。
业界通常采用的策略是,采用已有的历史负载作为基准数据,然后在此基础上进行适当调整。具体到执行层面,通常的做法是,录制已有的实际用户负载,然后在此基础上做以下两部分修改:
- 录制数据的清洗,将录制得到的真实数据统一替换成为压测准备的数据,比如,需要将录制得到的真实用户替换成专门为压测准备的测试用户等等·;
- 基于用户模型的估算,在全链路压测过程中,按比例放大录制脚本的负载。
最后,再用这个负载来模拟全链路压测的负载。
## 真实交易和支付的撤销以及数据清理
由于全链路压测是在真实的生产环境中进行的,那么完成的所有交易以及相关的支付都是真实有效的,所以我们就需要在测试结束后,将这些交易撤销。
因为,我们已经对这些交易的流量和数据进行了特定标记,所以我们可以比较方便地筛选出需要撤销的交易,然后通过自动化脚本的方式来完成批量的数据清理工作。
除了上面的四大问题以外,全链路压测还需要考虑测试执行过程中的性能监控、高强度压测负载下的测试熔断机制、全链路压测执行期间对原有系统正常负载的影响、全链路压测数据对外的不可见等等。
所以说,全链路压测的技术含量很高,而且需要多方共同配合才有可能顺利完成。所以,今天这篇文章的目的,意在抛砖引玉。希望你可以借由这篇文章,先对全链路压测的难点以及对应的解决思路有个全局的认识。而如果你想要更好地了解并掌握全链路压测,最好的方式还是要在实际项目中多加历练。
另外,你还可以参考一些网上的优秀资源,我在这里列出了两条供你参考:
<li>
[https://mp.weixin.qq.com/s?__biz=MzIzMzk2NDQyMw==&amp;mid=2247486703&amp;idx=1&amp;sn=0c448c40469e6a8f32476a7c7fbab6cd&amp;source=41#wechat_redirect](https://mp.weixin.qq.com/s?__biz=MzIzMzk2NDQyMw==&amp;mid=2247486703&amp;idx=1&amp;sn=0c448c40469e6a8f32476a7c7fbab6cd&amp;source=41#wechat_redirect)
</li>
<li>
[https://www.cnblogs.com/imyalost/p/8439910.html](https://www.cnblogs.com/imyalost/p/8439910.html)
</li>
## 总结
今天这篇文章,我和你分享了全链路压测的基本知识,以及在开展全链路压测的难点、对应的解决思路。现在,我再和你一起回顾下。
全链路压测,是基于真实的生产环境来模拟海量并发用户请求和数据,对整个业务链路进行压力测试,试图找到所有潜在性能瓶颈点并持续优化的实践。它的应用领域不仅仅包含验证系统在峰值期间的稳定性,还会包含新系统上线后的性能瓶颈定位以及站点容量的精准规划。
了解了全链路的基本概念,以及适用场景后,我和你分享了全链路压测中最关键的四个技术难点,即:海量并发请求的发起、全链路压测流量和数据的隔离、实际业务负载的模拟,以及测试完成后的数据清理。
- 海量并发请求的发起主要借助于JMeter并且通过Jenkins Job来实现海量并发的调度控制
- 全链路压测流量和数据的隔离主要借助含有特定标记的流量和数据来实现,同时需要对业务模块以及中间件进行必要的改造,数据库这边还会使用影子数据库;
- 实际业务负载的模拟,主要是采用基于历史流量修改后的回放来实现;
- 全链路压测完成后的数据清洗,则是借助自动化的手段来批量完成。
## 思考题
你能想到全链路压测中还有哪些技术上的难点吗?
感谢你的收听,欢迎你给我留言一起讨论。

View File

@@ -0,0 +1,95 @@
你好,我是茹炳晟。
首先感谢大家对《软件测试52讲》专栏的支持与参与。
到目前为止我已经通过测试基础知识、GUI自动化测试、API自动化测试、代码级测试、性能测试、测试数据准备、测试基础架构、测试新技术8个系列、47篇文章和你分享了软件测试相关的所有知识点。
每篇文章后面我都为你留下了1~2个思考题。其中一部分思考题是让你分享你所在项目和团队的实践和其他读者一起探讨、交流这样大家可以互相借鉴好的做法还有一部分思考题是针对当篇文章中的内容希望你可以分享一些你的想法也想借此了解你在实际的测试工作中遇到的问题尽我的能力再多为你提供些帮助。
47篇文章的写作基本上已经占满了我所有的个人时间。1000多条留言我也没有精力去一一答复这其中还有很多不是一两句就能解释清楚的问题。还有些留言质量非常高分享了一些我未覆盖到的内容观点都非常赞。
所以,特别选在专栏即将结束的节点,也可以说是和你分享完了软件测试的基本概念、原理、方法的节点上,我和编辑一起策划了这个“答疑解惑”系列,从已发布的文章,以及对应的留言中,精选出一些问题,为你解答。
当然了我的专栏还有5篇正文没有更新我已经根据大家的反馈重新调整了这5篇文章的主题选择了大家最关注的、对大家更有帮助的五个技术点和你展开分享。下周我将继续为你更新这些文章敬请期待。
今天这篇文章,我就先挑选了五个问题,和你分享一下我的看法。你也可以继续在留言区给我留言,说出你的见解,我们继续讨论。
## 问题一:从拓展思维的角度,还可以为“用户登录”功能补充哪些测试用例?
在专栏第一篇文章[《你真的懂测试吗?从“用户登录”测试谈起》](https://time.geekbang.org/column/article/10030)中,我从“用户登录”功能的测试用例设计谈起,和你分享了一个看似简单的功能,在设计测试用例时需要考虑的方方面面。在文后,我希望你可以从拓展思维的角度,思考一下还可以为这个“用户登录”功能补充哪些测试用例。
大家针对这个问题的留言质量都非常高,考虑的也都非常全面,可以说涵盖了很多我在文章中并没有涉及到的点。
你也许已经发现了,针对“用户登录”这个简单直接的功能,我们居然可以设计出这么多的测试用例。这些测试用例,既覆盖了明确定义的软件功能性需要,也覆盖了软件非功能性需求的方方面面。
可是当在实际项目的实施过程中当老板让你预估一下测试一个“用户登录”功能需要多少时间和工作量的时候如果完全按照文章中的介绍的测试用例设计方法来执行测试的话你可能会告诉老板说“我需要至少2-3天”。此时你的老板一定会火冒三丈怀疑你是不是在忽悠他就这么个简单明了的功能居然要花这么长时间的测试。
因此,这么全面的测试设计和执行通常不会出现在实际的工程项目中。站在工程实践的角度,**我推荐的是“够用就好”的原则**。
其实,测试的目的并不是要求软件中不存在任何错误,而是希望软件在上线运行的过程中,错误不会被触发。这就要求我们在测试用例选择的过程中,要尽可能覆盖用户最常使用的操作场景进行重点测试,同时也应该基于风险的大小来决定哪些测试应该纳入当前的测试范围。这里的风险指的是,万一软件缺陷被触发将会对业务造成哪些影响。
## 问题二:你有哪些好的测试用例设计实践和方法?
在专栏的第二篇[《如何设计一个“好的”测试用例》](https://time.geekbang.org/column/article/10150)文章中,我和你分享了一个“好的”的测试用例应该具备的特征、常用的几种测试用例设计方法,以及三个独家“秘籍”。相应地,我也希望你可以在留言区分享一些好的实践和方法。
大家在留言区的评论很活跃,也很精彩。这里,我再和你说说我的一些实践和方法吧。
<li>
我在文章中分享的方法都是从技术层面展开的,其实还有很多**流程上的方法**可以帮助测试用例的设计。比如一些资深的测试工程师可以将一些典型的测试用例设计整理成检查点列表Checklist。这样当你完成测试用例设计后可以再基于检查点列表来自查你的用例设计是否还存在不完备的地方。
</li>
<li>
通常情况下,测试用例的设计需要通过文档来体现。所以,你往往会花费很多的时间在文档写作上,而不能将有限的精力用在“刀刃”上。为了减少设计测试用例的文档写作时间,二把更多的时间花在测试用例的设计上,我建议你**引入一些速记工具,或者是“头脑风暴”类的工具**,来简化测试用例设计的文档工作。
</li>
<li>
**“小黄鸭”方法**不仅适用于程序的调试,同样适用于测试用例设计的自我检查。“小黄鸭”方法原本的含义是,当你在调试程序的过程中,因为无法顺利找到问题源头而无法继续的时候,可以假想有一个小黄鸭是你的听众,然后你将程序实现的思路以及业务逻辑处理的细节一一讲给它听。这样在讲述的过程中,会引发你全面的思考,并可以帮助你自发地发现问题。同样地,你也可以将测试用例的设计思路讲给小黄鸭听,以此来帮助你理清思路。
</li>
## 问题三:你在实施单元测试时,遇到了哪些问题,又是如何解决的?
在专栏的第三篇文章[《什么是单元测试?如何做好单元测试?》](https://time.geekbang.org/column/article/10275)中,我和你分享了单元测试的概念,和你重点讨论了用例的组成,以及在实际项目中开展单元测试的方法。在文后的思考题中,我希望你可以分析一下你所在公司在实施单元测试时遇到了的问题,以及对应的解决方案。
在留言区我也看到了一些读者的见解也很受益。这里我首先会分享一下eBay在开展单元测试时的实践然后再挑选一位回答得很精彩的用户做下点评。
eBay是全球知名的大型电子商务网站已经大规模使用了微服务架构。对于单元测试而言eBay并不会对所有的微服务以及所有的中间件全面开展单元测试。我们只会选取一些偏底层的核心应用来全面开展单元测试而对于产品的前端代码、偏业务应用的代码很少会执行完整意义上的单元测试。
如果你在项目中推行过单元测试,并且要求能够提供代码级的覆盖统计数据的话,那么你在实施和推行单元测试的过程中,一定会遇到诸如单元测试代码覆盖率低下的问题。这里,**我的建议是,在项目的早期不要硬性规定绝度百分比的代码覆盖率指标,而是建立一个覆盖率基线,然后保证代码在每次发布前,都可以与这个基线持平或者高于这个基线的覆盖率。**
另外,我还在留言区看到了一个非常具有代表性的留言,也就是这个叫作“小志”的读者留言。
<img src="https://static001.geekbang.org/resource/image/e7/96/e723abf9ba55f91b493c623cd22dfb96.jpg" alt="" />
他很好地归纳了当今互联网企业中单元测试的现状。的确,很多的互联网公司都在追求快速的功能实现,却一直没有强调单元测试,并且由于灰度发布机制的支持,所以对软件质量隐患的容忍度比较高。这点和传统软件测试的观念差别比较大,因为传统软件测试没有灰度发布的概念,所以对每个即将发布版本的质量控制都会非常严格。
## 问题四:你所在项目开展的自动化测试,真的有必要吗?
在第四篇文章[《为什么要做自动化测试?什么样的项目适合做自动化测试?》](https://time.geekbang.org/column/article/10483)中,我和你分享了自动化测试的概念,以及具备哪些特征的项目才适合做自动化测试。我还希望你能理解自动化测试是一把“双刃剑”,必要一味地为了自动化而自动化。
所以,在文后我希望你根据自己所经历的项目中的自动化测试所占比重,去进一步思考这个项目开展自动化测试的必要性。
这里我先来分享一下eBay在自动化测试方面的具体实践。eBay早期是非常重视GUI自动化测试的所以投入了大量的资源去大规模开发GUI测试用例。可是随着用例规模的不断扩大GUI测试的稳定性问题也被不断放大。同时大量GUI测试用例的并发执行时间也成了个大问题。
为了缓解这种状态,我们逐渐**将测试重心迁移到了后端服务的API测试上**。API测试具有代码形式统一、执行稳定性高的特点。而原本GUI测试我们降低了自动化测试用例的比例并由探索式测试来完成部分GUI测试。
另外,在留言区,我看到了一些比较赞的观点。比如,这位“关柱鹏”的留言,就是站在了全局的视角描述了可重用的测试架构。这样的架构设计将非常有利于自动化测试脚本的应用。你可以参考。
<img src="https://static001.geekbang.org/resource/image/ca/56/ca616dd335efe168984f5eb4b5ebd256.png" alt="" />
## 问题五:你所在公司,开展代码级测试时用到了哪些自动化测试技术?
在专栏的第5篇文章[《你知道软件开发各阶段都有哪些自动化测试技术吗?》](https://time.geekbang.org/column/article/10572)中我和你分享了在软件的全生命周期中涉及到的自动化自动测试技术。我从单元测试、代码级集成测试、Web Service测试以及GUI测试阶段的自动化技术这四个方面和你分享了“自动化测试”的技术内涵和外延。
我希望你读完这篇文章后,可以回忆或者归纳下:你所在公司,开展代码级测试时用到的自动化测试技术。
这里我还是先和你分享一下eBay的实践经验。可以说eBay非常重视自动化测试开发并在这方面投入了很多成本几乎在软件研发生命周期的各个阶段都有自动化测试的支持。
比如在单元测试阶段有基于参数分析的自动化测试数据准备系统在API测试阶段有基于REST Assured的API自动化测试在系统测试或者E2E测试中用到了GUI自动化框架设计与开发。可以说自动化测试已经渗入到了eBay软件研发的各个领域。
在留言区中,“康美之心 淇水之情”的留言在我看来是一个能够很好的落地实践。Spring-boot、REST Assured、Cucumber都是当下最热门的技术。由于使用了Cucumber所以完全有可能可以实现自己特有的基于API的行为驱动开发BDD
一方面Cucumber本身就是非常成熟的BDD框架另一方面REST Assured也支持三段式的测试用例描述。所以用Cucumber结合REST Assured的方案可以实现更灵活的API级别的BDD用Cucumber结合Selenium可以实现GUI级别的BDD。
<img src="https://static001.geekbang.org/resource/image/74/a6/7400afd58053c44bcf6b74ada838e4a6.png" alt="" /><br />
最后,感谢你能认真阅读这五篇文章的内容,并留下你的学习痕迹。相信这些留言,于你于我而言,都是一笔宝贵的财富。期待你能继续关注我的专栏,继续留下你对文章内容的思考,我也在一直关注着你的留言(虽然有时未能及时回复)。

View File

@@ -0,0 +1,143 @@
你好,我是茹炳晟。
今天的“答疑解惑”系列文章,我们一起来解决测试新技术、测试人员的互联网架构核心知识这最后两个系列相关的问题。
这期的答疑文章,我不会针对每篇文章后面的思考题展开,而是会选择了四个大家比较关注的问题,和你分享我的观点。如果你的看法不同,或者你还有哪些其他问题的话,欢迎你在这篇文章下面给我留言,我会持续不断地解答你的问题。
当然了,我还是会先用一句话简单概括下每篇文章的内容,并给出对应的链接,方便你复习。
## 测试新技术系列文章回顾
**在专栏的第43篇文章[《发挥人的潜能:探索式测试》](https://time.geekbang.org/column/article/41203)中**,我和你阐述了这样一个基本思想:探索式测试是一种软件测试风格,而不是一种具体的软件测试技术。
作为一种思维方法,探索式测试强调依据当前语境与上下文选择最适合的测试技术,并强调独立测试工程师的个人自由和责任,其目的是为了持续优化其工作的价值。
看到有用户在留言中说到想在实际项目中开展探索式测试,这里我想再给个建议:
高效开展探索式测试的前提是,对被测系统的设计以及行业应用有非常清晰的认识,同时在此基础上以发散的方式对系统可能存在的缺陷进行探索。所以,这就要求测试人员不仅要具有很深的业务领域知识,还需要很强的逻辑推理和分析能力。而这样的人才,属于比较稀缺的。
另外,探索式测试不要到了项目后期再集中展开,而是应该在各个模块级别就尽可能多地去探索,尽量在测试早期就能发现问题。
需要注意的是,一定不要在执行层面,将探索式测试变成了随机测试,你设计的所有后续测试步骤都必须是在你之前的步骤上推演出来的。而且,在执行探索性测试的过程中,你需要明确每个操作的目的是什么,是想证实自己的推论还是要推翻自己的假设。对此,你一定要做到心中有数,否则很容易就会变成无明确目的随机测试。
而从管理层的角度来看,千万不要以探索式测试发现的缺陷数量来考核团队的绩效。因为这样不仅不能提升测试效率,反而会把大量的时间浪费在一些非核心功能的测试上。
**在专栏的第44篇文章[《测试先行测试驱动开发TDD》](https://time.geekbang.org/column/article/41238)中**我和你分享了TDD的核心思想是在开发人员实现功能代码前先设计好测试用例编写测试代码然后再针对新增的测试代码来编写产品的功能代码最终目的是让新增的测试代码能够通过。
正如“叶夏立”在留言中所说TDD如何落地才是最核心的问题。所以我会将这个问题作为今天这篇文章要回答的第一个问题和你分享些我的经验。
**在专栏的第45篇文章[《打蛇打七寸:精准测试》](https://time.geekbang.org/column/article/41368)中**,我通过分析传统软件测试的短板,和你分享了精准测试的概念、必要性、核心思想,以及具体的测试方法。
因为这种测试理念,国内外成功落地的案例非常少,而这个理论也是由星云测试公司提出的,所以我借鉴了《星云精准测试白皮书》中的内容,并从我的视角为你解读了其中的部分内容。如果其中有哪些不清楚的问题,我们可以一起探讨,共同进步。
**在专栏的第46篇文章[《安全第一:渗透测试》](https://time.geekbang.org/column/article/41608)中**,我分享了渗透测试是由专业的安全专家来模拟黑客对系统发起攻击,找到并修复系统的安全漏洞,从而让真正的黑客无机可乘。在这其中,我和你详细分享了渗透测试的知识点,包括常用的测试方法、步骤、工具。
这篇文章更新后,有的用户反馈希望看到实例的演示,这样可以更生动、易于理解,所以这里我决定在今天的第二个问题中,和你分享一个实际的渗透测试实例,满足你的需求。
**在专栏的第47篇文章[《用机器设计测试用例:基于模型的测试》](https://time.geekbang.org/column/article/41781)中**我分享了基于模型的测试MBT是一种基于被测系统的模型由工具自动生成测试用例的软件测试技术。这也就决定了相对于传统软件测试技术来说有优优劣。
所以我们需要综合考虑项目本身的特点和人员的技术水平以此决定是否有必要开展MBT。关于如何判断你的项目是否适合开展MBT我决定作为今天的第三个问题和你展开分享。
## 测试人员的互联网架构核心知识系列文章回顾
**在48篇文章[《优秀的测试工程师为什么要懂大型网站的架构设计?》](https://time.geekbang.org/column/article/42373)中**我主要和你分享了测试人员学习网站架构知识的why、what、how的问题并提出了“由广度到深度”和“自上而下”的架构学习思路希望可以增强你学习网站架构的信心。
**在第49篇文章[《深入浅出网站高性能架构设计》](https://time.geekbang.org/column/article/42569)中**我从测试人员的视角和你分享了网站的高性能架构设计包括哪些部分以及在设计测试用例时需要着重考虑哪些点。而设计到具体的测试方法、工具问题你可以再回顾一下第28~34篇文章也就是性能测试系列文章中的相关内容。
**在第50篇文章[《深入浅出网站高可用架构设计》](https://time.geekbang.org/column/article/42509)中**,我将影响网站高可用的因素归为了三类(即:服务器硬件故障、新应用的发布、应用程序本身的问题),并相应地给出了解决这三类问题的方案。希望这些内容可以帮到你。
**在第51篇文章[《深入浅出网站伸缩性架构设计》](https://time.geekbang.org/column/article/42894)中**,我和你分享了一个网站的可伸缩性架构设计主要包含的两个层面。其中,一个是指根据功能进行物理分离来实现伸缩,另一个是指物理分离后的单一功能通过增加或者减少硬件来实现伸缩。
**在第52篇文章[《深入浅出网站可扩展性架构设计》](https://time.geekbang.org/column/article/44185)中**,我和你分享了本专栏的最后一个主题,即网站的可扩展性架构设计。从已有的实现方案来看,实现网站可扩展性架构的主要技术手段包括事件驱动架构和微服务架构。
而在微服务的实现方案中需要测试人员关注的点你可以参考第24篇文章[《紧跟时代步伐微服务模式下API测试要怎么做](https://time.geekbang.org/column/article/13581)中的相关内容。所以,在这篇文章中,我和你重点分享的是事件驱动架构实现的大致原理,以及测试人员需要额外关注的点。
因为这个系列的文章,更新日期比较近,所以很多用户还没来得及看。所以,我就没有在这篇答疑文章中,设置与这个系列有关的问题。如果你阅读完这个系列的文章,有任何困惑,都可以给我留言,我将和你一起讨论、解决。
## 问题一什么样的项目适合TDDTDD如何才能落地
的确TDD这个概念从提出来到现在已经有很长时间了但实际落地的项目并不多甚至可以说少之又少。造成TDD落地困难的原因有很多比如很多大型项目本身就不适合做TDDTDD初期阶段的工作划分以及粒度控制都是难点。但我认为最重要的原因是TDD需要大幅改变研发团队的流程规范。这种改变在公司层面尤其是中大型公司是很难实际执行的。
虽然明知落地TDD困难重重但是你又特别想在自己的项目中尝试TDD以解决现在的测试方法不能解决的问题。那么落地TDD有哪些可值得借鉴的经验呢这也正是很多用户关心的比如昵称为“叶夏立”的用户在文章下面的留言。
<img src="https://static001.geekbang.org/resource/image/57/32/578839d18ed80a668bb45bd201bbd732.png" alt=""><br>
这里,我根据自己的时间,为你总结了如下几点:
- 只在一些小型项目比如前期的POC项目中尝试开展TDD
- 一定要借助Cucumber之类的TDD或者BDD工具来协助TDD的开展
- 必须把控好每个测试用例的粒度,不能太大,也不能太小,需要与开发函数以及功能的粒度相匹配;
- 项目管理的流程必须去适应TDD的实践原本管理的是需求现在管理的可能是测试用例了因为用例本身就是对需求的解读
- 测试人员必须要有开发背景否则TDD只能是空谈
- 必须要得到管理层的大力支持,最好是能自顶向下的推广。
## 问题二:渗透测试在落地的时候,需要注意哪些问题?
首先说一下,我设立这个问题的初衷,是想通过一个实际的例子,来帮助你理解渗透测试的本质。
所以我以最常见的SQL注入攻击为例和你简单分享下渗透测试落地时需要主要的问题。假设我现在要测试用户登录功能用户登录时会在界面上分别输入用户名userName和密码passWord然后程序代码会将输入的userName和passWord填充到下面SQL语句中。
```
SELECT * FROM users WHERE (name = '&quot; + userName + &quot;') and (pw = '&quot;+ passWord +&quot;');&quot;
```
假设我们输入的用户名是“Robin”密码是“12345678”。那么此时的SQL语句如下所示
```
SELECT * FROM users WHERE (name = 'Robin') and (pw = '12345678');&quot;
```
然后系统就会使用这个SQL语句去数据库中查询是否存在该用户以及该用户的密码是否正确。
此时,如果你是黑客希望通过渗透来非法获取系统信息,你就会尝试设计以下的用户名和密码:
```
username 输入 &quot;1' OR '1'='1&quot;;
password 输入 &quot;1' OR '1'='1&quot;;
```
这种情况下用于数据库查询的SQL语句就会变成如下所示的样子就是将userName和password的部分用 "1 OR 1='1"都代替:
```
SELECT * FROM users WHERE (name = '1' OR '1'='1') and (pw = '1' OR '1'='1');&quot;
```
如果你熟悉SQL语句的语法你就会发现黑客查询数据库使用的SQL语句其实和下面这个SQL语句是等价的
```
SELECT * FROM users;
```
也就是说原本用于查询单条用户信息的SQL语句已经被黑客改造成了获取全部用户信息的SQL语句。这就是最典型的SQL注入攻击手段了。
而我们所讲的渗透测试,就是会去人为模拟这种攻击,以判断系统是否能够成功应对此类攻击。
## 问题三如何判断你的项目是否适合采用MBT以及你认为会遇到哪些问题可能会阻碍MBT的开展呢
一般来讲只要系统的设计可以用状态转移图来描述的话基本都可以采用MBT。另外基于GUI的系统因为本身就可以画出页面之间相互跳转的关系图所以也适合采用MBT。
很可惜eBay内部的项目除了一些实验性的尝试并没有大规模开展MBT。但据我所知业界最近有一家初创企业AutoTest正在全力推进MBT的落地和应用而且还发表了很多[相关文章](https://mp.weixin.qq.com/s/6RwTJlf7uEquCadMp1jnbw),如果你对此感兴趣可以去关注一下。
在我看来阻碍MBT落地的最关键问题有两个
- 一个是,探索路径的有效性问题。早期的实施方案,完全基于图论来覆盖可能路径,造成了大量的非法或者不合理的路径。但是,近几年来由于人工智能的介入,大大提升了路径探索的有效性。
- 另一个是如果只是用MBT完成单纯测试的话收益比会比较低。只有将MBT和自动化测试结合在一起才能发挥MBT的优势。在这方面eBay一直在尝试试图将Selenium和MBT集成到一起目前已经有了初步成果实现了用模型导出实际可以执行的自动化测试用例的POC。
## 问题四:测试工程师如何应对面试?
首先,我并不鼓励为了应对面试,而去做特别的准备,你还是应该在平常的工作中多积累。**面试的过程,本来就是尽可能地反映你真实的技术水平以及业务熟练程度的交流,关注的重点应该是如何将你自己掌握的技术和知识更好地展现出来,而不是把你不懂的知识包装成你已经“懂”的知识**。为此,我有如下几点小建议供你参考:
- 当被问及相关测试工具的时候,除非问到了该工具使用上的细节,否则尽可能避免谈及工具使用的细节,而是应该更多地阐述工具本身的原理、和同类工具相比的优劣势,以及这个工具可以以什么样的方式帮你解决问题。这时,你的视野一定要高,不能局限于细节。当然,这也就要求你能够充分理解这个工具的原理和使用方法。
- 当被问及特定算法实现的时候,刚开始的时候,一定不要试图去寻求最优解法,而是要考虑最基本的实现,然后在此基础上迭代优化。因为,优秀的面试官希望看到的不是最优解,而是你解决问题的过程,以及在这个迭代过程中的逻辑推理。
- 当被问及你所不熟悉的测试技术时,如实回答就好,不要试图去掩饰。很多时候面试官看重的并不是你知不知道,而是当你不知道的时候你会怎么做。
最后感谢你能认真阅读第43~52这10篇文章的内容并写下了你的想法和问题。期待你能继续关注我的专栏继续留下你对文章内容的思考我也在一直关注着你的留言、你的学习情况。
咱们的答疑环节暂告一段落了,但这并不意味着结束。如果你在学习过程中遇到了什么问题,还可以继续给我留言,我会持续不断地回答你的问题。

View File

@@ -0,0 +1,118 @@
你好,我是茹炳晟。
今天这篇文章是“答疑解惑”系列文章的第三期在这一期里面我做了个小小的改变不再是针对每一篇文章后面的思考题以及“你”的留言来展开分享。这次我选择将这个专栏的第二个系列GUI自动化测试系列作为一个整体回答下你的问题。
根据目前GUI测试技术的应用情况以及“你”在留言中留下的期望进一步了解的问题也为了能够讲清、讲透我还是选择了五个问题为你解答。当然了如果你关注的问题并未涵盖其中的话也不要有遗憾你可以在这篇文章下继续给我留言我会持续关注并回答你的问题。
接下来我还是会先为你总结一下GUI自动化测试系列的全部10篇文章的内容并为你提供文章链接希望你可以通过回顾旧文获得新知。
## 系列文章内容回顾
**在专栏的12篇文章[《从0到1你的第一个GUI自动化测试》](https://time.geekbang.org/column/article/11913)中**我基于Selenium 2.0带你从0到1建立了一个最简单直接的GUI自动化测试用例。通过这篇文章我希望传达给你的内容是基于Selenium搭建GUI自动化测试用例的方法以及Selenium 1.0、2.0的实现原理。所以对于具体的用例设计方面的细节比如构建一个GUI测试用例时需要封装哪些类等我并没有详细展开。
也正如“Cynthia”在留言中所说的一些资料会直接带你分析源码但不会为你讲述工具的原理所以虽然你会用这个工具但是类似于为啥Chrome可以跑的case、Firefox跑不了、为啥Web Driver还要一个浏览器装一个这种问题你永远不会明白。反馈到具体的测试工作上就会出现知道要这么做但是不知道为什么要这么做的尴尬局面。
**在专栏的第13篇文章[《效率为王:脚本与数据的解耦 + Page Object模型》](https://time.geekbang.org/column/article/11966)中**我和你分享了什么是数据驱动的测试让你明白了“测试脚本和数据解耦”的实现方式以及应用场景然后我从GUI自动化测试历史发展演变的角度引出了GUI测试中的“页面对象模型”的概念。
在这篇文章最后,我希望你思考一下“是否应该在页面对象模型中封装控件的操作”这个问题。我看到留言区的回复,也都很精彩,可谓是思维清晰、逻辑严谨。这里,我想再阐述一下我的观点,详情请见问题二。
**在专栏的第14篇文章[《更接近业务的抽象:让自动化测试脚本更好地描述业务》](https://time.geekbang.org/column/article/12135)中**,我以“如何把控操作函数的粒度”和“如何衔接两个操作函数之间的页面”这两个问题为引子,和你分享了业务流程的概念、核心思想和适用的场景。
说实话,看到这篇文章下面的留言我很感动,为什么呢?因为我分享的测试思想得到了你的认可,也吸引你围绕着这一个主题展开了讨论。在这些留言中,我也仿佛看到了自己当年为了做好某一项测试而尝试的一系列方案。所以,在此我也想对你道声感谢。
**在专栏的第15篇文章[《过不了的坎聊聊GUI自动化过程中的测试数据》](https://time.geekbang.org/column/article/12399)中**我从创建测试数据的技术手段和时机两个方面和你分享了在实际项目中需要综合运用API调用和数据库操作来创建测试数据并根据测试数据自身的特点分而治之地采用On-the-fly和Out-of-box的方式以寻求数据稳定性和数据准备效率之间的最佳平衡。
因为这个专栏后面有一个单独的系列去讲测试数据准备的那些事儿了,所以今天我就不再过多地展开这个问题了。当然,你在也可以在这篇文章下面,留下你关注的与测试数据相关的问题,等到测试数据准备系列的文章答疑时,我再挑选些典型问题进行解答。
**在专栏的第16篇文章[《脑洞大开GUI测试还能这么玩Page Code Gen + Data Gen + Headless》](https://time.geekbang.org/column/article/12401)中**,我一下和你分享了页面对象自动生成、测试数据自动生成、无头浏览器这三种技术。或许,在你看来有些停留在概念层面了。
说到为什么我没有针对某一个具体的概念展开分享其实我是这么考虑的页面对象自动生成主要用到的就是QTP这个工具而对这个工具的使用你可以通过它的文档来轻松上手并且这个工具的内部实现也没有对外公开所以这部分内容完全从工具使用的角度来讲的话 并不能发挥这个专栏的价值。同样地,测试数据自动生成、无头浏览器也是这个道理。我还是希望你能在知道了这些概念之后,可以结合自己的实际工作,动手实践,这样的效果才是最好的。
所以,今天我也就不再过多的展开这个话题了。如果你在落地这三个概念的时候有任何问题,也可以给我留言,希望可以帮到你。
**在专栏的第17篇文章[《精益求精聊聊提高GUI测试稳定性的关键技术》](https://time.geekbang.org/column/article/12403)中**我为你归纳了五种造成GUI自动化测试不稳定的主要因素非预计的弹出对话框、页面控件属性的细微变化、被测系统的A/B测试、随机的页面延迟造成控件识别失败以及测试数据问题。然后我针对每种问题给出了对应的解决思路。
当时为了不淹没提高GUI测试稳定性的关键技术这个主题我并没有通过实例展开这五个因素及其对应的解决方案。今天为了加深你的理解我决定针对随机失败的重试retry和你分享一个实例作为今天我要回答的第三个问题。
**在专栏的第18篇文章[《眼前一亮带你玩转GUI自动化的测试报告》](https://time.geekbang.org/column/article/12558)中**我和你分享了一份理想的GUI自动化测试报告应该包括哪些内容并和你分享了eBay在全球化GUI测试报告中的创新设计。希望这些方法你也可以经过适当改进用到自己的测试项目中。
有些读者感觉这篇文章不够过瘾想要知道某一个技术细节的实现。所以这里我会针对基于GUI测试报告和你再分享一个小例子和你说说故事板样式的GUI测试报告具体是如何实现的也就是后面我要分享的第四个问题。
但是,我还是想要再强调一下,这篇文章的设计初衷并不是去解释每种报告的实现细节,而是帮助你从多元化的视角去思考一个高效的测试报告应该是什么样的。
**在专栏的第19篇文章[《真实的战场如何在大型项目中设计GUI自动化测试策略》](https://time.geekbang.org/column/article/13047)中**我从“实战”的角度分享了实际的大型全球化电商网站的GUI自动化测试如何开展希望可以帮你解决测试策略如何设计、测试用例脚本如何组织这两个问题。
其实通过这篇文章我已经和你说清楚了大型项目中的GUI自动化测试策略这个问题所以在今天这篇文章中我就不再继续展开这个话题了。
**在专栏的第20篇文章[《与时俱进:浅谈移动应用测试方法与思路》](https://time.geekbang.org/column/article/13168)中**我和你分享了Web App、Native App和Hybrid App这三类移动应用的测试方法以及移动专项测试的思路与方法。其实这三类移动App的测试和GUI自动化测试的思想是相通的只不过是针对移动应用自身的特点又有了一些独特的方法而已。
**在专栏的第21篇文章[《移动测试神器带你玩转Appium》](https://time.geekbang.org/column/article/13310)中**我用Appium手把手地带你实现了一个移动应用的测试用例并本着知其所以然的原则和你分享了Appium的实现原理希望借此可以带你玩转Appium完成自己的移动应用测试。
这两篇关于移动App测试的文章更新后大家留言都很踊跃也可以反映出大家很关注这块内容。所以今天我再选择微信小程序的自动化测试和你再分享下业界的主流工具以此作为今天的最后一个问题。
## 问题一目前互联网企业在GUI测试上的投入在不断减少而为什么我要花这么多精力去讲GUI测试
这个问题,很多人都想知道答案。那么我就说说这么设计的考量吧。
当前互联网产品的测试重点的确逐渐在向后端API迁移GUI自动化测试所占比重越来越低出现这种情况的原因主要有两个
- GUI自动化测试用例的ROI一直上不去投入较大。一方面测试用例本身还很难做到100%的稳定;另一方面,被测系统界面发生变化时,测试用例的维护成本一直高居不下。
- 微服务架构的普及使得后端逻辑可以被重用到大量的前端界面中比如同一个后端API既可以通过PC端的浏览器请求来访问也可以通过移动端Native App的请求来访问此时保证后端API的质量就成了保证前端质量的基础。也是因为这个原因API测试取代了部分GUI自动化测试。
这么说来我们完全就应该把测试重点放在API端而没必要花很大的精力去做GUI的自动化测试。但现实情况是如果你没有站在终端用户的角度对系统基本业务功能通过用户实际使用的GUI做过测试你是否敢直接发布上线。
很多时候后端API的功能都正常并不能保证前端的GUI功能测试就一定没有问题。所以现在很多互联网企业依然会在GUI自动化测试上做投入只不过是将GUI自动化测试用例的设计原则从原本“全面覆盖”进化成为了“只覆盖最基本的核心业务功能”。
## 问题二:是否应该在页面对象模型中封装控件的操作?
这其实是个测试架构设计的问题,而且一直以来都有争议。
**如果在页面对象中封装控件的操作**,实现起来相对简单,而且符合传统的面向对象的设计思想,即:一个对象既有对象描述又有对象操作。
但是,从测试架构的层次上来看,这种设计不够规整,而且将对象的识别和操作进行了耦合。而这种耦合就意味着需要对对象的识别和操作一同进行更新和版本管理,但现实情况是对象的识别需要经常更新,而对象的操作相对来说很稳定,这种不必要的依赖关系又增加了测试的维护成本。
**如果将页面对象和对象的操作分开封装**,即:让对象操作的类依赖于对象定义的类。这种设计,在测试架构的层次上来看比较清晰,而且可以分别来实现页面对象识别和对象操作的版本管理。同时,如果你已经采用了页面对象自动生成技术,就可以直接生成页面对象类,从而保证页面操作类的稳定。这样做的好处也很明显,即能够以自动化的方式来降低由页面变化引起的改动工作量。
由此可见这两种方式各有优劣。那么根据我的经验来看对于初级阶段的GUI自动化测试直接在页面对象中封装控件操作的方式更简单直接而随着GUI自动化测试不断成熟在需要考虑引入页面对象的版本管理以及页面对象的自动生成的时候将页面对象和对象的操作分开封装的方式就是大势所趋了。
## 问题三如何通过重试retry机制来应对由随机的页面延迟造成的控件识别失败
正如我在第17篇文章[《精益求精聊聊提高GUI测试稳定性的关键技术》](https://time.geekbang.org/column/article/12403)中提到的,重试可以是步骤界别的,也可以是页面级别的,甚至可以是业务流程级别的。
而在这其中,**最下面的一层重试机制是在控件操作这一层的**。比如,控件识别失败的时候,我们会在自动化测试框架层面发起重试。一般来讲,我们会在自动化测试框架中的控件操作函数上封装重试逻辑,而且默认情况下,我建议你可以启用这个级别的重试。
**再往上一层是业务流程也就是Business Flow的重试**。如果一个业务操作失败了,我们就可以考虑重新执行这个业务流程。
但是,这其中需要特别注意的是, 业务流程对数据本身可能存在依赖,所以业务流程重试的合理性需要根据测试用例的上下文来决定,尤其要关注测试数据是否可以支持可重复执行。
一般来讲我们会在自动化测试框架中实现Business Flow的重试。但是我建议默认关闭该功能只在你确定需要进行业务流程级别的重试时才显式启用Business Flow层面的重试。这么做的主要原因是业务流程的重试会涉及测试数据的问题只有当你非常肯定业务流程的重试不受测试数据的影响时我们才会人为启用业务流程级别的重试。
**最上面一层是测试用例级别的重试**。当一个测试用例执行失败的时候,我们可以考虑重新执行整个测试用例,一来希望排除随机出错的可能,二来是评估出错的步骤是否可以重现。
这种测试用例级别的重试一般是由CI流水线完成的而不是由自动化测试框架实现的。CI流水线会整理出所有失败的测试用例列表然后在CI流水线脚本中发起重试。
## 问题四故事板样式的GUI测试报告具体是如何实现的
故事板样式的GUI测试报告指的是按时序对GUI操作界面进行截图生成的测试报告。对于这类报告的实现主要考虑两个方面的因素
- 一是获取屏幕截图。这一步我们可以通过封装控件操作函数来实现比如在自行封装的click函数中先调用截图函数然后再调用真正的click操作。
- 二是截图在报告中的展现形式。这一步我们可以直接使用现成的HTML5的PPT框架这样我们只要按照框架要求来生成屏幕截图的数据结构即可而无需去关注复杂的HTML5的处理逻辑。
这里我强烈推荐reveal.js。eBay就是用这个框架开发了自己的故事板样式的GUI测试报告。其中在第18篇文章[《眼前一亮带你玩转GUI自动化的测试报告》](https://time.geekbang.org/column/article/12558)中的测试报告截图就是基于reveal.js实现的。关于reveal.js的详细用法和数据结构请参考[这里](https://revealjs.com/#/)。
## 问题五:关于微信小程序的自动化测试,以及用到的测试工具。
很多读者在留言中问到了微信小程序的测试问题,这里我稍微展开下。
其实,微信小程序的测试,在测试设计和执行思路上同移动端测试并没任何区别。那为什么很多人会问到微信小程序的测试呢?
我觉得主要原因是,在实际开展自动化测试的时候,由于缺少专业的、有效的工具,使得微信小程序的测试在我们看来难以执行。
其实呢有一款来自腾讯的微信小程序测试工具XTest就是个不错的选择可以很方便地支持测试用例的录制。这里有一篇使用这个工具进行实际[小程序测试的文章](https://www.cnblogs.com/Test-xiaobai/p/9066331.html),你可以从中获得一些使用细节。
最后感谢你能认真阅读第12~21这10篇文章的内容并写下了你的想法和问题。期待你能继续关注我的专栏继续留下你对文章内容的思考我也在一直关注着你的留言、你的学习情况。
感谢你的支持,我们下一期答疑文章再见!

View File

@@ -0,0 +1,137 @@
你好,我是茹炳晟。
今天这篇文章是“答疑解惑”系列文章的第二期我还是选取了五个问题。这五个问题来自于第6~11篇这6篇文章其中第9和第10篇这两篇文章中的两个问题被我合并为了一个问题并且我会针对这个问题再次为你简单梳理一条学习路径。
然后我还会选择这6篇文章下的精彩留言为你稍作解答、分析。
在这篇文章中,我依旧为你添加了每篇文章的链接,并用一句话概括了这篇文章的主要内容,你也可以再次回到这篇文章中,回忆一下第一次阅读后的想法,看看第二次阅读又有了哪些新的感想。欢迎你继续给我留言,我仍在关注着你的问题、反馈,希望可以为你提供更多的帮助。
现在,我们就开始今天的五个问题吧。
## 问题一:你在使用代码覆盖率工具的时候,遇到过哪些“坑”?
在专栏第6篇文章[《你真的懂测试覆盖率吗?》](https://time.geekbang.org/column/article/10759)中我针对代码覆盖率这个主题和你分享了代码覆盖率的的价值、局限性并结合JaCoCo分析了代码覆盖率工具的实现原理。这也是这个专栏中第一篇为你讲解某种测试工具实现原理的文章希望你可以认真体会。
通过阅读这篇文章,我希望你回顾一下曾用过的代码覆盖率工具,并说说你的使用感受和遇到的“坑”。
留言中,我也看到了一些留言很精彩,提到了自己使用代码覆盖率工具的一些实践。所以,也很感谢你们的分享。
接下来,我再和你分享下,在使用代码覆盖率工具时可能面临的两个最大的问题:
1. **测试覆盖率越往后越难。**
统计代码覆盖率的根本目的是,指导用户的测试用例设计。也就是说,我们要通过代码覆盖率的结果去发现哪些代码没有被执行到,以此为依据再去设计有针对性的测试用例。
在这个过程中你会发现前期达到一个不错的覆盖率指标比如70%)还是比较容易的,但是越往后就越难提高了。
因为后期没有覆盖到的代码往往都是一些出错异常分支的处理为了能够覆盖这部分内容往往需要构造特殊的数据和环境。很多时候这些数据和环境并不好得到就不得不采用各种Mock的手段来实现。
因此,在实际项目中,到底要不要一定到达很高的覆盖率,就应该根据项目情况结合风险驱动的概念来综合分析了。
1. **推行代码覆盖率的初期阶段,很难要求很高的覆盖率指标。**
代码覆盖率的挑战并不是来自于技术本身而是来自于管理。很多公司在刚刚推行覆盖率统计的时候会发现各个模块和项目的覆盖率普遍较低有些甚至还不到20%。这时,我们就不应该依靠行政手段来强行规定高的代码覆盖率。
因为这会在短时间内增加很多工作,一来会引起开发人员的抵触与反感,二来会耽误项目本身的进度。此时最好的做法是采用持续改进的策略,也就是随着迭代更新,代码覆盖率不允许出现下降的趋势,至少保持持平或者逐渐增长的态势。
## 问题二:你在填写软件缺陷报告时,还有哪些好的实践值得分享呢?
在专栏第7篇文章[《如何高效填写软件缺陷报告?》](https://time.geekbang.org/column/article/10936)中,我分享了想要把发现的缺陷准确无歧义地表达清楚,一份高效的软件缺陷报告应该包括的内容,以及需要注意的问题。
在这篇文章最后,我希望你分享一下自己在填写软件缺陷报告时,还有哪些好的实践。
在这里,我想再和你分享另外一个观点。你在实际提交软件缺陷的时候,有没有感觉这个过程很繁琐。对于缺陷的重现规律和步骤需要做很多尝试,然后写文档时还有很多工作量,比如需要考虑措辞和语句的组织,这往往会花费你不少时间。那有没有什么好方法可以减少写文档的工作量吗?
其实,对于传统软件的开发流程来讲,这种重量级的缺陷报告是必须的。特别是对于一些大公司来说,开发人员和测试人员可能散布在全球不同时区的地域,这种严格的缺陷文档就很有必要了。
但是,现在的很多互联网企业,尤其是国内的互联网企业,所有的工程技术人员都在一个办公室,而且普遍采用敏捷开发的模式,此时面对面地沟通软件缺陷的效果将远远好于文档描述,而缺陷报告本身的作用也会退化成一条简单的记录。
所以,**缺陷报告的详细程度应该在很大程度上取决于团队特征。**
另外,我发现读者在文章的留言中也提出了很多建设性的方法。比如,下面这位昵称为“卫宣安”的读者,提出了让开发人员主动来认领缺陷的方式。如果说所有的开发人员都具有很强的责任心,同时系统规模也不是太大,或者说报告的缺陷数量不是很多的情况下,这的确是解决问题的一个好思路。但是,当团队规模比较大,缺陷数量也比较多的时候,要求每个开发人员都去挨个查看所有缺陷的效率就会很低。
<img src="https://static001.geekbang.org/resource/image/18/03/18b02affdd921cdf2b41347a28a03a03.png" alt="" />
那么在这种情况下我们是否有更好的方法来解决这个问题呢答案就是采用基于AI和机器学习的缺陷分类方法。我们可以通过缺陷的特征值提取并结合分类算法对缺陷应该归属的团队进行自动分类。
在eBay的自动化测试体系中就有专门的系统对失败用例和缺陷做自动进行分类。
## 问题三:你觉得在实际工程项目中,一份高效的测试计划应该包括哪些内容?
在第8篇文章[《以终为始,如何才能做好测试计划?》](https://time.geekbang.org/column/article/11063)中,我和你分享了虽然在敏捷开发模式下,软件测试不再局限于厚重的、正式的计划文档,但是测试计划的重要性丝毫没有发生变化。一份成功的测试计划,依旧必须要清楚地描述出测试范围、测试策略、测试资源、测试进度和测试风险预估这五个最重要的方面。
而在读完这篇文章之后,我希望你思考的是,在一份测试计划中,除了这五个最最关键的内容外,你觉得在实际工程项目中还需要再增加的内容,以及是不是所有的项目都需要有很详实的测试计划。
其实很多时候, 你会发现计划的速度远远赶不上变化,尤其是互联网产品的开发。就像下面这两位用户在留言中描述的现象,相信你在实际的工作中一定遇到过类似的场景。
<img src="https://static001.geekbang.org/resource/image/01/fc/014a7d773a20633c499a4f9bc45310fc.png" alt="" />
<img src="https://static001.geekbang.org/resource/image/ab/1b/ab3f85cc62c291c45190adc9006ac81b.png" alt="" /><br />
所以,这个时候,**你有没有反问过自己一个问题,此时文档化的详细测试计划还真的有必要吗?或者说有没有可能采用轻量级的测试计划。**
首先,轻量级的测试计划并不是说没有计划,而是指计划的文档化表现形式应该尽可能简单,只是用一些关键词来描述纲领性的东西。这样做,一来可以降低测试计划本身的写作时间;二来当测试计划由于各种原因发生变化的时候,也可以非常快速灵活地进行修改和更新。
其实目前的敏捷开发模式比如Scrum模式下的测试计划就会在每个Sprint最开始的时候以非常轻量级的方式来确定测试计划有些时候甚至可以没有文档化的测试计划。这时关于测试范围、测试策略和测试设计之类的内容都在测试人员的脑子中。
注意,这时候虽然没有书面的测试计划,但并不代表说没有测试计划。
## 问题四:软件测试工程师的高效进阶路径是什么?
我在第9篇文章[《软件测试工程师的核心竞争力是什么?》](https://time.geekbang.org/column/article/11325)和第10篇文章[《软件测试工程师需要掌握的非测试知识有哪些?》](https://time.geekbang.org/column/article/11453)中,分别和你分享了一个软件测试工程师需要具备的核心竞争力,以及需要掌握的非测试专业知识。看到这两篇文章后面,有很多用户留言说:觉得很迷茫,抓不住自己要重点培养的能力、要怎么快速学习。
虽然今年7月6日我在极客时间做直播时回答过这个问题但这里为了帮助你快速找到一条适合自己的道路我就再简单为你梳理下。
首先我把在软件测试岗位上工作了0~5或者0~3年的工程师划分为初级测试人。为什么有这个划分呢因为0-5年工作经验的测试工程师往往工作的中心都还是在软件产品测试本身还没有将测试上升到质量工程的高度。当然了我这里说的测试指的是广义上的测试包括功能测试、自动化测试、性能测试等各个方面。
然后,我把初级测试人可以进阶的方向,归纳为了三类:
<li>
**业务专家**,也就是业务功能测试方向;
</li>
<li>
**开发测试工程师**,也就是自动化测试方向,指的是把业务功能的测试转换成自动化的脚本;
</li>
<li>
**测试开发工程师**,指的是负责开发测试平台、工具,以及服务。
</li>
接下来,我就简单总结下,向每个方向进阶的相对高效的路径吧。
**首先,如果你想成长为一名业务专家的话,那你就需要精通于某一项具体的测试业务**比如说电子商务网站、EPR系统和SAP系统等等。这样的角色更像是产品经理你需要能准确把握业务产品的定位了解整个业务流程的操作、用户的使用习惯以及如何提到整个产品的转化率。
而要成为这样的人,你首先需要在该领域中有较长时间的积累,能够从真正的终端用户视角来使用被测软件,能够对该软件应用领域的行业知识有比较清楚的了解。
但精通于某一个业务领域的缺点是,一旦离开了这个业务领域,之前的业务积累就没用了。
**其次,如果想要成长为一名开发测试工程师的话,你平时需要积累高效的测试用例组织方法、对自己用到的测试框架的优劣势有深入理解,并在使用某种测试工具时要深入到其原理的层面。**
这样的话你就可以快速具备测试用例设计、测试框架选型、灵活运用测试工具的技能。并且你也会因为这种长期的“知其所以然”的积累可以从容应对新的技术趋势。比如说你掌握了Selenium 1.0、2.0的实现原理后对API测试的原理也就可以做到触类旁通了。
**最后,如果想要成长为一名测试开发工程师的话,那你需要培养的是开发能力,以及测试意识**。说白了,测试开发工程师,更像是一个开发人员,只不过需要在理解测试上下文的基础上,为其他测试工程师开发一些平台、工具、服务。这时,我建议的成长路径,就是一个开发工程师的成长路径了。
## 问题五:你觉得你现在团队采取的自动化测试策略,有哪些好的地方,又有哪些需要改进的?
在第11篇文章[《互联网产品的测试策略应该如何设计?》](https://time.geekbang.org/column/article/11462)中,我和你分享了互联网产品的特性决定了它采用的测试策略,遵循的是“重量级 API 测试,轻量级 GUI 测试,轻量级单元测试”的原则,更像是一个菱形结构。这与传统软件产品的金字塔测试策略有所区别。
而在文章最后,我希望你可以针对你所在公司采取的测试策略,谈谈自己的看法。
这里我可以给你分享一下eBay的自动化测试策略的演变和发展路径希望可以帮助你理解什么叫作因地制宜地选择和设计最适合你的自动化测试策略。
eBay在早期阶段也和现今大多数公司一样采用的是基于GUI来大规模开展自动化测试。尤其早期阶段的网站本身还不是太复杂而且还不是现在的微服务架构所以基于GUI的自动化测试在页面对象模型和业务流程模型的支持下能够很好地完成业务功能的验证和测试。
这个阶段我们关注的重点是通过GUI层面的操作来对整个网站的业务功能进行验证。
可是后来随着业务的不断发展与壮大基于GUI的测试用例数量不断增长同时再加上浏览器兼容性测试等的要求测试用例的数量越来越多测试执行的效率也越来越低下所以单靠GUI测试已经很难满足全面测试的要求了。
再加上系统架构本身也从原本的单体应用逐渐发展成为了微服务甚至是服务网格的架构形式同时普遍采用了前后端分离的架构设计所以此时的测试重点也就从原来以GUI为主转变成了以后端API为主的阶段。
此时GUI测试只会去覆盖一些最最基本的业务功能而API测试则会关注各种参数的组合以及各种边界场景。
通过这个实际的例子,我们可以看出,**并不存在一个放之四海而皆准的自动化测试策略。测试策略的选择,在很大程度上取决你的测试诉求以及被测系统本身的架构设计。**
最后感谢你能认真阅读第6到11这六篇文章的内容并写下了你的想法和问题。期待你能继续关注我的专栏继续留下你对文章内容的思考我也在一直关注着你的留言、你的学习情况。
感谢你的支持,我们下一期答疑文章再见!

View File

@@ -0,0 +1,141 @@
你好,我是茹炳晟。
今天的“答疑解惑”系列文章我们一起来解决性能测试系列中7篇文章的问题。你可以通过下面对每篇文章的简单总结回顾一下文章内容也可以点击链接回到对应的文章复习。
现在,我们就开始今天的问题吧。
## 问题一:你在性能测试项目中,选择具体的系统吞吐量指标时,会考虑哪些因素呢?
在专栏的第28篇文章[《带你一起解读不同视角的软件性能与性能指标》](https://time.geekbang.org/column/article/14577)中,我首先从终端用户、系统运维人员、软件设计开发人员和性能测试人员,这四个维度介绍了软件系统的性能到底指的是什么;然后,和你分享了软件性能的三个最常用的指标:并发用户数、响应时间、系统吞吐量。
而在这篇文章最后我针对系统吞吐量提出了这样一个问题系统吞吐量的表现形式有很多比如“Requests/Second”“Pages/Second”“Bytes/Second”等你在性能测试项目中选择具体的系统吞吐量指标时会考虑哪些因素呢
其实**选择哪种类型的吞吐量指标,和你的测试目标以及被测系统的特点是息息相关的。**
如果你的被测系统是后台处理系统而且你的测试目标是要优化它的处理能力那么这个时候你的关注点必然就是每秒能够处理的请求数量即Requests/Second。当然如果你发现你的后台处理能力有可能是受限于网络传输的带宽那么这个时候你就可能需要去考虑“Bytes/Second”这种类型的吞吐量指标了。
总结来讲,选取哪个吞吐量指标,取决于你最关注的内容。
下面这位昵称为“假装乐”的读者的留言很典型,是很多刚刚结束性能测试的同学都会有的疑惑。
<img src="https://static001.geekbang.org/resource/image/f7/4e/f72b9275cb073e41a79ed3a371befa4e.png" alt="">
其实,性能测试应该贯穿于软件研发生命周期的各个阶段:
- 单元测试阶段就要衡量代码级别的时间复杂度和空间复杂度,以及多线程并发情况下的功能准确性等等;
- 每个API也需要进行单独的性能测试和评估
- 集成测试阶段需要考虑跨组件或者模块的数据大小,以及缓存的使用情况等等;
- 系统测试阶段,还需要从模拟终端用户负载的角度来衡量系统全局的性能指标等等。
说到底,一个最基本的原则就是,性能问题一定是越早发现越容易定位,也越容易被修复。而到了软件研发生命周期的后期,性能问题的定位成本和复杂度会呈指数级增长。
所以,如果你有机会去了解大型软件公司的测试的话,就会发现它们没有所谓的性能测试团队,而是有一个性能工程团队。这个团队会从软件研发生命周期的各个阶段去测试、评估和优化软件的性能。
## 问题二:你在实际工程项目中,接触过性能测试的哪些方法,其中遇到了哪些问题,又是如何解决的?
在专栏第29篇文章[《聊聊性能测试的基本方法与应用领域》](https://time.geekbang.org/column/article/14832)中,我通过一个医院体检的例子,和你分享了并发用户数、响应时间和系统吞吐量这三个指标之间的关系和约束;然后,又和你分享了性能测试七种常用方法,以及四大应用领域。
在这篇文章最后,我希望你能够分享一下你在实际开展性能测试时,都遇到过哪些问题,又是如何解决的。虽然这篇文章的留言比较少,但也能从中看出大家在开展性能测试的时候,确实也如我当初一样,遇到了各种各样的问题。
那么,现在我就来和你分享一下性能测试中可能遇到的一些典型问题吧。
其实性能测试中可能会遇到的问题实在是太多了架构中的各个层面、每个软件模块、模块配置、数据库中的数据量、多线程的锁机制、进程设计、JVM配置参数、数据库配置参数以及网络参数等等都会成为性能测试中的问题。
可以说,性能测试的问题,只有你想不到的,没有你遇不到的。所以,如果我通过一个实际案例和你分享的话,肯定会是长篇大论,有违答疑系列文章的设计初衷。为什么?因为性能测试的问题,一般都和架构、设计、配置、数据量有着密不可分的关系。所以,**我今天会通过一个简化的案例,和你展开分享,意在抛砖引玉。**
首先,我想问你一个问题:当你做压力测试的时候,你觉得硬件资源占用率是低好,还是高好?很多人可能会说,当面对大量并发请求的时候系统资源占用率当然低好。因为资源用得少,说明系统后续的容量可以继续大幅度扩充。
听起来很有道理,但真的是这样吗?
我就遇到过一个测试当你不断加大并发访问量的时候系统CPU的使用率一直处在15%左右不管并发用户数如何加大CPU的使用率一直上不去但是事务响应时间却随着并发用户的上升而有持续上升的趋势。所以一定是有某些机制限制了CPU的使用。
其实在这种情况下我们希望看到的是随着并发用户数的不断增长这些CPU敏感性的并发操作会尽可能多地去使用CPU的计算能力而不是现在这种CPU使用率上不去的情况。
为此我分析了这部分的代码逻辑发现其中使用了一个固定大小的数组来存放并发任务进程的句柄当这个数组满了的时候新进程的创建处于阻塞状态只有之前的进程处理结束后数组中出现了空位新的进程才会被创建。当时这个数据的大小是128也就是最多只能有128个并发进程同时运行我当时就怀疑这是限制CPU使用率的主要原因。
为了验证这个想法我直接将这个固定数组的大小调整成了256然后继续并发测试。果然CPU的使用率徘徊在30%左右,就验证了我的猜测。
那么,接下来就需要修复这个问题了。显然,这是一个设计上的问题,压根儿这里就不应该采用固定大小的数组,而是应该采用可变长度的数据结构。
## 问题三:你接触过哪些后端性能测试工具?你认为这款工具中,有哪些好的设计吗?
在专栏第30篇文章[《工欲善其事必先利其器:后端性能测试工具原理与行业常用工具简介》](https://time.geekbang.org/column/article/16589)中,我以问答的形式,和你分享了后端性能测试的理论,以及工具使用的问题。这也是这个专栏中,唯一一篇采用问答形式的文章,有没有感觉读起来比较省力呢?
因为我后面增加了一篇JMeter的加餐文章所以这里我也就不再过多地介绍后端性能测试工具了。这次我来回答一下“Robert小七”提到的问题。
正如我在今天的第一个问题中提到的,高效的性能测试一定是从源头抓起的,也就是研发的每个阶段都需要进行性能测试,而不是等到系统开发完了,再一次性地进行黑盒级别的性能测试。
所以对每个API的性能测试是非常必要的。而且很多公司比如eBay等都会对每个API进行独立的性能测试。其实在对API开展独立的性能测试之前还需要在一些关键代码上做基于函数方法的性能测试和评估。直到这些都完成了以后才会开展基于性能场景的测试。
<img src="https://static001.geekbang.org/resource/image/43/ae/43ee756010f0cb6066d0ad21a42cdbae.png" alt="">
## 问题四:你在工作中接触过哪些前端性能测试工具,它们各自有什么特点呢?
在专栏的第31篇文章[《工欲善其事必先利其器:前端性能测试工具原理与行业常用工具简介》](https://time.geekbang.org/column/article/17935)中我以一个具体网站为例和你分享了使用WebPagetest进行前端性能测试的方法以及前端性能相关的主要概念与指标。
在这篇文章最后,我希望你可以分享一下自己曾使用过的前端性能测试工具。
在这里,我来分享下我的经验吧。
前端性能测试工具除了我在文章中介绍的WebPagetest比较常用的还有YSlow但是这些工具的基本原理是类似的所以如果你已经掌握了我在这篇文章中介绍的WebPagetest的原理的话对于YSlow等前端性能测试工具的原理基本就可以做到触类旁通了。
此外,有些公司还会特别关注一些特定的前端性能指标。这些性能指标,一般不能从性能测试工具中直接得到,需要自行定制开发。
这个昵称为“木然”的用户提出的问题很典型。很多刚开始使用WebPagetest的同学都会有这个疑问但是很不幸WebPagetest是无法来做这种需要登录才能访问到的页面的前端性能调优的。
<img src="https://static001.geekbang.org/resource/image/ac/d0/ac703d8ac228a08a29c870d80b983fd0.png" alt="">
WebPagetest这类工具的初衷就是纯粹站在前端页面优化的角度来设计的本身并不会涉及业务操作所以对这块的支持很弱。虽然WebPagetest支持Http Auth以及自定义脚本的扩展但是Http Auth还是会受到服务器端本身配置的影响而自定义脚本的扩展还受限于特定的浏览器所以实际的应用价值有限也很少有人去用。
而至于有什么更好、更灵活的方法来处理这种需要登录,以及特定业务操作的前端页面性能优化,很可惜,目前我并没有什么好的方案。如果你对此有一些好的想法或者实践的话,就给我留言一起讨论吧。
## 问题五:在实际工作中,获取并细化性能测试需求,需要怎么做,注意哪些问题呢?
在专栏的第32篇文章[《无实例无真相基于LoadRunner实现企业级服务器端性能测试的实践](https://time.geekbang.org/column/article/18120)和第33篇文章[《无实例无真相基于LoadRunner实现企业级服务器端性能测试的实践](https://time.geekbang.org/column/article/23268)中我从最基础的性能测试需求获取、LoadRunner的原理开始和你分享了基于LoadRunner实际开展企业级服务器端性能测试的整个过程。
通过这两篇文章,我希望能够帮你快速建立服务器端性能测试的全局观,并了解各主要步骤的关键技术细节。其实,正如我在文中所说的,在开展整个性能测试的过程中,测试需求的获取是其中最关键、最难的一个环节。这里我再针对测试需求的获取,和你分享一个实例吧。希望可以真正帮到你。
很多时候,**我们从产品经理那里拿到的需求是很笼统的,必须经过必要的分析和细化才能转换为可以用于性能测试场景设计的需求**就像文章中提到的“每天支持完成8000个体检”的例子。这样的例子还有很多比如我们经常可以看到类似“系统最大支持500万用户同时在线”的需求这同样是一个看似具体实则非常笼统的性能需求。
500万用户在线这些在线的用户在具体执行什么类型业务操作对后端服务器造成的压力差别是巨大的。比如这500万个用户都在执行查询操作和这500万个用户什么不做对后端服务器的压力是天壤之别的。
那么这里需求获取的难点就是要能够准确估算这500万在线用户执行的各种类型的业务操作所占的百分比只有这样才能真实、客观地反应后端服务器承受的实际压力。
但是除此之外,**还有很多的性能需求并不是直接从产品经理那里获取的,而是需要资深的性能测试人员根据以往的经验,以及同类系统和竞品的业务流量来自己估算。**
比如产品经理不会告诉你一个实现具体业务的API操作应该要在多长时间内完成产品经理也不会明确告诉你在API层面的业务吞吐量是多少。这些测试需求都是需要性能测试人员来预估甚至是基于一些实验来细化的。
所以说,性能需求的获取是一个关键且困难的环节。
这个昵称为“Sunshine”的用户在留言中的问题虽然简单但也是个典型问题。我来和你一起分析一下。
关于如何实现每隔10 s增加100个用户的方法其实还算是简单。LoadRunner的场景设计界面中直接提供了该功能。你可以通过GUI界面填写你的用户增加策略比如在什么时间段内每多少秒增加或者减少多少个并发用户并且LoadRunner还会自动提供并发用户数随着时间变化的曲线图。你甚至可以直接修改这个曲线图来修改用户数量变化的规律使其符合你的需求。
另外场景设计中的很多配置都可以在LoadRunner的场景设计界面中实现。具体内容你可以参考[LoadRunner的使用文档](https://softwaresupport.softwaregrp.com/web/softwaresupport/document/-/facetsearch/attachment/KM02004789?fileName=LR_12.50_Tutorial_zh.pdf)。
<img src="https://static001.geekbang.org/resource/image/43/99/433801c5b0541872538648e3955ce199.png" alt="">
## 问题六:你所在企业,在开展性能测试时采用了哪些方法呢?
在专栏的第34篇文章[《站在巨人的肩膀:企业级实际性能测试案例与经验分享》](https://time.geekbang.org/column/article/39704)中,我挑选了最重要的四类性能测试方法(性能基准测试、稳定性测试、并发测试,以及容量规划测试),和你分享如何在实际项目中完成这些测试,确保软件的性能。
通过这篇文章,我希望可以帮助你从整体上理解性能测试,形成一个体系知识。而在这篇文章最后,我希望你能够分享一个你所在企业采用的性能测试方法,大家互相取长补短。
对于eBay这样的大型全球化电商企业性能测试除了文章中提到四类性能测试方法以外还会开展一些其他类型的性能测试。
- 对于关键业务代码以及中间件代码的核心算法部分,一般都会开展基于时间复杂度和空间复杂度的代码级别的性能评估;
- 对于各个独立的中间件或者公共服务组件本身,也会开展性能基准测试和容量规划测试;
- 对于基于微服务的各个API接口会开展性能基准测试和压力测试
- 对于前端Web页面会开展基于前端性能的调优
- 对于整体系统,会不定期开展全链路压力测试,其中还会使用历史流量回放等技术来模拟海量实际的并发场景。
以上这些是从性能测试的类型来讲的。从性能测试工具的支持上来看eBay还建立了一些内部使用的公共性能测试平台任何人都可以通过这些性能测试平台方便地发起压力负载而不用去关心诸如Load Generator之类的细节对于后端性能测试以及API性能测试你只要上传压测脚本和性能测试场景设计就能很方便地发起测试。这个很像淘宝对外提供的PTS服务。
其实,上述的这些方法适用于很多的互联网产品。而至于到底实施哪几条,则取决于你想通过性能测试希望达到什么样的目的。
最后感谢你能认真阅读第28~34这7篇文章的内容并写下了你的想法和问题。期待你能继续关注我的专栏继续留下你对文章内容的思考我也在一直关注着你的留言、你的学习情况。
感谢你的支持,我们下一期答疑文章再见!

View File

@@ -0,0 +1,108 @@
你好,我是茹炳晟。
今天的“答疑解惑”系列文章我们一起来解决测试数据准备和测试基础架构这两个系列8篇文章中的问题。你可以通过下面对每篇文章的简单总结回顾一下文章内容也可以点击链接回到对应的文章复习。
这两个系列下的文章留言已经很少了,或许是你没有坚持学习,也或许是这部分内容并没有切中你现在的痛点。毕竟,广义上的软件测试,包括了测试数据平台、测试执行平台等,而我们也不能每一种都有机会接触。
但这里,我想再给你打打气,有些知识虽然你在接触时感觉自己不会用到,但随着技术发展、公司业务转型,或者是你个人的职业晋升,都会需要越来越宽广的知识面,这也正应了我在专栏里面提到的一个比喻,**测试工程师通常是“广度遍历”,关注的是“面”**。所以,坚持学习,才是我们从“小工”蜕变为“专家”的正确路径。
## 问题一:有些时候,我们需要创建消息队列里的数据,这类数据应该如何创建呢?
在第35篇文章[《如何准备测试数据?》](https://time.geekbang.org/column/article/39924)中我从测试数据创建的维度和你详细分享了生成测试数据的四种方法基于GUI操作生成测试数据、通过API调用生成测试数据、通过数据库操作生成测试数据以及综合运用API和数据库的方式生成测试数据。
其实,我们要创建的测试数据并不仅仅局限于数据库,很多时候还需要创建消息队列里面的数据。所以,在阅读完这篇文章后,我希望你可以思考一下如何处理这类问题?或者,请你分享一下你曾经是如何解决这个问题的。
这里,我来分享下我的方法吧。
通过模拟消息队列中的测试数据,可以实现各个被测模块之间的解耦,这个思路非常关键。至于如何来模拟消息队列中的测试数据,在技术上其实没有任何难度。
我们通常的做法是在测试数据工具的底层封装一个工具类这个工具类内部通过调用消息队列的API或者操作接口函数来实现消息队列的CRUD操作然后凡是需要改变消息队列中数据的地方都通过这个工具类来完成实际操作。
## 问题二:你所在公司,采用是什么测试数据策略?为什么选用了这种策略?
在专栏的第36篇文章[《浅谈测试数据的痛点》](https://time.geekbang.org/column/article/40006)中我和你分享了选择不同时机去创建测试数据是为了解决不同的数据准备痛点。为了解决这些痛点我的经验是把测试数据分为“死水数据”和“活水数据”其中“死水数据”适合用Out-of-box的方式而“活水数据”适合采用On-the-fly的方式。
在这篇文章最后,我希望你可以分享一下自己项目中采用的是什么测试数据准备策略,以及会不会使用线上真实的数据进行测试。
这里我来分享下eBay在准备测试数据时的策略吧。
eBay在准备测试数据时采用的并不是单一的某种方法而是针对实际的业务场景选取了不同方法最后将这些方法进行组合完成整个测试的数据准备工作。可谓是多管齐下。
这里我和你分享下eBay主要使用了的几种策略
- 能用API的地方就一定不用数据库操作
- 数据库操作只用在API无法支持以及需要批量创建性能测试数据的场景
- 对于“活水数据”比如订单和优惠券等一定采用On-the-fly的方式实现测试数据用例内的自维护
- 对于“死水数据”比如商品类目和品牌等一定采用Out-of-box的方式来提高测试数据准备的效率
- 对于性能测试的背景数据,采用生产环境的实际数据(注意,这里使用的实际生产数据是经过了必要的“脱敏”操作的);
- 对于复杂数据采用了预先在系统中预埋template数据然后在需要使用的时候通过复制template数据然后再修改的策略
- 对于生产环境的测试,除了全链路压力测试,都会采用真实的数据来进行。
所以测试数据策略的选择最重要的是适合自己所在的公司或者项目的实际情况。这里我和你分享的eBay的实践希望可以在针对特定场景选择测试策略的时候可以感到有据可依。
## 问题三如果你所在公司也处于测试数据1.0时代,你们还用到过哪些测试数据准备函数的实现方法吗?
在专栏的第37篇文章[《测试数据的“银弹”- 统一测试数据平台(上)》](https://time.geekbang.org/column/article/40156)和第38篇文章[《测试数据的“银弹”- 统一测试数据平台(下)》](https://time.geekbang.org/column/article/40166)中,我从全球大型电商企业早期的测试数据准备实践谈起,和你一起分析这些测试数据准备方法在落地时遇到的问题,以及如何在实践中解决这些问题。
我希望通过这种遇到问题解决问题的思路可以带着你去体会时代的演进理解测试数据准备技术与架构的发展历程并进一步掌握3.0时代出现的业内处于领先地位的“统一测试数据平台”的设计思路。
正如我在文中所说目前大多数企业都还处于测试数据1.0时代。其实这也很正常。因为1.0时代的测试数据准备函数才是真正实现数据创建业务逻辑的部分后续测试数据准备时代的发展都是在这个基础上在方便用户使用的角度上进行的优化设计。所以说测试数据1.0时代是实现后续发展的基础。
其实对于测试数据准备函数的内部逻辑实现来说除了我在文章中提到的基于API、数据库以及API和数据库相结合的三种方式以外还有一种方法也很常用尤其适用于没有API支持的复杂测试数据场景。
这种方法就是,事先在数据库中插入一条所谓的模板数据,在下一次需要创建这类数据的时候,就直接从模块数据种复制一份出来,然后再根据具体的要求来修改相应的字段。
这里需要特别注意的是对于1.0时代的测试数据准备函数来说,我们还需要建立工具的版本管理机制,使其能够应对多个不同的数据版本。
## 问题四目前Selenium Grid已经有Docker的版本了你有没有考虑过可以在云端搭建Selenium Grid呢
在专栏的第39篇文章[](https://time.geekbang.org/column/article/40468)[从小作坊到工厂什么是Selenium Grid如何搭建Selenium Grid](https://time.geekbang.org/column/article/40468)[](https://time.geekbang.org/column/article/40468)中我从测试基础架构的概念讲起并和你分享了传统Selenium Grid 和基于Docker的Selenium Grid的搭建方法。
不知道你有没有在课后去尝试搭建Selenium Grid呢这其中是否遇到了什么问题如果你遇到了问题欢迎你给我留言我将帮助你一起解决。
在这篇文章最后我希望你可以畅想一下是否可以在云端搭建Selenium Grid。这里我结合eBay的探索来谈谈我的看法吧。
对于一些大公司来说在云端来搭建Selenium Grid已经被证明是切实可行的而且也已经呈现出逐渐向云端过度的趋势。这主要得益于云端部署的易维护性和上云本身的便利性。
比如eBay已经实现了在PCF上基于Docker来运行Selenium Grid的方案其中落地的难点在于配置Docker的网络和IP地址。主要原因是PCF会为部署的应用提供统一App URL的命名转换。
从本质上讲只要Selenium Grid是基于Docker实现的那么上不上云本身并没有本质区别。但是考虑到将来的App以及所有的后台服务都会逐渐向云端过度所以测试基础架构这块必然也会遵循这个趋势和App以及后台服务的环境保持在一个技术栈上将会减少公司整体基础架构的多样性从而提高研发效能。
## 问题五:你觉得测试基础架构的设计和搭建过程中,还有哪些点需要再优化呢?又可以从哪些方面进行创新呢?
在专栏的第40篇文章[《从小工到专家:聊聊测试执行环境的架构设计(上)》](https://time.geekbang.org/column/article/40582)和第41篇文章[《从小工到专家:聊聊测试执行环境的架构设计(下)》](https://time.geekbang.org/column/article/40915)中,我首先和你分享了测试执行环境的概念,然后为你剖析了测试基础架构的演进历程,希望可以帮助你理解测试基础架构的设计,最终可以定制一套适合自己的测试基础架构。
学习完这两篇文章,我希望你思考的是,你所在团队,还可以再测试执行环境的架构设计上,进行哪些优化和创新?
其实测试基础架构的优化和创新都是由问题本身驱动的。如果不是为了解决实际遇到的问题企业是不会为了追求更新的技术而去寻求测试架构的改进方案的。所以通常情况下我们都是在测试或者DevOps的过程中遇到了问题或者瓶颈才会考虑新的技术与方法。
- 比如我在文中提到的,为了解决大量测试用例在短时间内执行完成的要求,才出现了测试执行集群的架构;
- 再比如,当测试用例数量非常多,每次测试结束,需要分析所有失败的用例时,就必须要考虑基于机器学习的缺陷分类方法;
- 再比如为了增加测试环境的有效使用时间避免开发人员要在发生缺陷的环境上实时Debug而造成的测试环境占用问题我们就会考虑在测试用例执行失败的时候自动获取全链路的日志
- 再比如如果我们的大量测试执行请求都是API调用我们就可以实现完全基于Docker的并发执行环境。
除了上面这些技术驱动的原因外还有些是由企业的组织结构驱动的。比如eBay的某些产品线CI/CD团队在印度而测试架构团队在中国。大家都知道CI/CD的流水线脚本和测试执行是强耦合的而要求两个异地团队实时合作并保证完全同步很困难。为此我们就需要考虑为CI/CD提供统一的测试接口这样流水线脚本就可以以解耦的方式与测试集成了。
## 问题六:你觉得在我给出的全球化电商的测试基础架构中,还可以增加哪些与测试相关的服务?
在专栏的第42篇文章[《实战:大型全球化电商的测试基础架构设计》](https://time.geekbang.org/column/article/41014)中,我根据自己的实践经验,把大型全球化电商网站全局测试基础架构的设计思路归纳为了“测试服务化”,并用一张图展示了整体的测试基础架构。
为了便于你回顾文章内容,我把文中用到的大型全球化电商网站的全局测试基础架构设计图,放到了这里。
<img src="https://static001.geekbang.org/resource/image/d9/71/d9456825d8e9568e9453efe5207fb571.png" alt=""><br>
其实,除了图中的各类测试服务以外,你完全可以根据你的业务场景来搭建更多的测试服务,以提高团队的测试效率和研发效能。
- 比如你可以提供完整和详细被测系统所有版本信息的服务通过一个简单的Restful API调用就可以得到被测系统中所有组件、各个微服务的详细版本信息还可以自动比较多个被测环境的版本差异。
- 再比如为了解决微服务测试过程中的依赖性你可以考虑提供基于消费者契约的统一Mock服务以契约文件作为输入来提供模拟真实服务的Mock服务从而方便微服务的测试。
- 再比如你还可以提供压力测试服务由这个服务统一管理所有的Load Generator来发起测试这个服务还可以进一步细分为前端性能测试服务以及后端压力测试服务。
这样的例子还有很多,**但在实际工作中,我们还是要根据测试本身的上下文以及被测产品的性质,来决定将哪些需求实现成测试服务会。**
假如,你的项目只是偶尔会做前端性能测试,那么你就完全没必要去自己实现前端性能测试服务,直接采用现成的工具效率会更高。而如果你的产品需要经常做前端性能测试和优化,而且还不止一个团队会需要这种类型测试的时候,你就应该考虑将前端性能测试服务化了。
最后感谢你能认真阅读第35~42这8篇文章的内容并写下了你的想法和问题。期待你能继续关注我的专栏继续留下你对文章内容的思考我也在一直关注着你的留言、你的学习情况。
感谢你的支持,我们下一期答疑文章再见!

View File

@@ -0,0 +1,130 @@
你好,我是茹炳晟。
今天的“答疑解惑”文章我将针对API自动化测试和代码级测试这两个系列6篇文章中的问题和你展开分享。
我还是会先简单概括下每篇文章的内容,并给出文章链接,帮助你复习相应的内容。同时,如果你再次阅读时还有哪些疑问的话,也欢迎你在文章下面继续留言。我会一直关注着你的学习情况,希望可以扫清软件测试精进道路上的障碍。
现在,我们就开始今天的主题吧。
## 问题一实际项目中往往会存在按时序的API调用以及异步API调用这类API测试要如何开展
在专栏的第22篇文章[《从0到1API测试怎么做常用API测试工具简介》](https://time.geekbang.org/column/article/13421)中我以基于主流Spring Boot框架开发的简单Restful API为例分别介绍如何使用cURL和Postman对其进行最基本的功能测试希望可以让你先对API测试有个感性认识。另外在这篇文章中我还和你分享了目前一些常见的典型复杂场景以及相应的测试思路和方法。
而在文章最后我希望你思考的是实际项目中往往会存在按时序的API调用以及异步API调用这类API测试要如何开展现在我来说说我的经验吧。
**我们先一起看看按时序调用的API序列的测试场景。**
对于此类测试我一般建议通过GUI操作来录制API的调用。比如在启用Fiddler的情况下通过GUI来完成业务操作随后去分析Fiddler抓取到的后端API请求顺序然后以此来开发API测试用例。
开发测试用例的过程中还需要特别关注前后两个API调用之间的数据传递比如需要将前一个API调用返回的response中的某个值作为参数传递给下一个API调用。
**其次是异步API的测试**。对于异步API测试的场景我们往往先会采取“只验证其是否发起了正确的调用而不直接验证操作结果”的方式。比如你的被测API是一个异步操作的API那么我只会去验证这个API是否按照预期发起了正确的异步调用请求而不会直接去验证异步操作的结果。如果这类测试全部通过后我们才会考虑真正验证异步操作结果的测试用例。
举个实际的例子假设你的被测API A完成的是下订单的操作。这个API A完成下订单操作要通过调用另外一个API B将订单信息写入到消息队列中去。而真正下订单成功指的是消息队列中的消息被后续服务正确处理并且成功了。此时这里的后续消息处理就是异步的操作了。
那么当我们要测试这个API A的时候我们只需要验证它是否正确地发起了对API B的调用即可而不用关心API B的具体行为结果。
也就是说我们只关注API A是否以正确的参数调用了API B即可而无需关注API B是否正确地执行了将订单信息写入消息队列的操作更不用关注消息队列中的消息被异步处理的结果。
注意这里的测试重点,应该更多地放在前面的部分,而真正验证异步操作结果的测试在资源有限的情况下只需覆盖最典型的场景即可。
## 问题二对基于配置文件的API测试框架你有哪些看法呢
在专栏的第23篇文章[《知其然知其所以然聊聊API自动化测试框架的前世今生》](https://time.geekbang.org/column/article/13565)中我和你分享了API自动化测试框架的发展历程帮助你理解API测试是如何一步一步地发展成今天的样子希望可以以这种“知其所以然”的方式加深你对API自动化测试的理解。
而在这篇文章最后我提到了基于配置文件的API测试框架比如典型的HttpRunner。在此类API测试框架的支持下测试用例本身往往就是纯粹的配置文件了。如果你用过这个框架的话我希望你可以谈谈你的看法。
对于基于配置文件的API测试框架的确是个不错的方向尤其是国内的开源框架HttpRunner更是推动了这种测试框架的普及。
**基于配置文件的API测试框架的优势可以归纳为以下三方面**
<li>
降低了测试用例开发的门槛使得完全没有代码基础的同学也可以很容易地完成API测试
</li>
<li>
可以很方便地将API功能测试用例直接转换成API性能测试的用例HttpRunner可以使用lucust直接实现这样的转换
</li>
<li>
同时HttpRunner这类工具还支持直接从网络转发工具得到的HAR中提取API调用的测试用例进一步降低了API测试用例的开发成本。
</li>
所以基于配置文件的API测试框架很受初学者的欢迎。
但是为了完成一些复杂场景的测试用例设计以及复杂的结果判断你还是需要具备基本的代码能力以完成这些复杂场景的测试实现。比如HttpRunner就会涉及到使用debugtalk.py来实现hook函数的功能扩展。
也就是说完全不写代码的API测试只能覆盖大部分的简单测试场景如果你要搞定复杂场景的API测试的话你是要必须掌握一些基本的开发技能这里没有任何捷径可走。
另外很多读者的留言也很精彩我这里特地选取了两条供大家参考。从Cynthia的留言中我看得出她已经完全习得了这篇文章中描述的方法的精髓这也正是我想要传达给你的最核心的内容。
<img src="https://static001.geekbang.org/resource/image/a6/ba/a67715406c2a7ae6e9bb98d2e3198eba.png" alt=""><br>
Martin在留言的后半部分中提到通过HttpRunner来实现轻量级的API测试的确是个好方法也最大程度地发挥了HttpRunner的价值。但是留言前半部分的“Postman转Python或者Java”的观点我并不是很认同。其实Postman是有直接代码转换功能的而且支持各种语言的各种框架基本可以实现一键操作所以其实很多没有采用HttpRunner的企业都还在普遍使用这个方法。
<img src="https://static001.geekbang.org/resource/image/5d/9c/5dc1be96cdacac1a510d10019e1cd59c.png" alt="">
## 问题三如果无法通过API Gateway方法得到契约的话应该采用什么方法来解决呢
在专栏的第24篇文章[《紧跟时代步伐微服务模式下API测试要怎么做](https://time.geekbang.org/column/article/13581)中我和你分享了微服务模式下的API测试旨在帮助你认清庞大的测试用例数量、微服务之间的相互耦合这两个问题的本质以更好地开展测试。所以我今天分享这个主题的目的就是帮你理解这两个问题的本质以及如何基于消费者契约的方法来解决这两个难题。
而在今天这篇文章最后我希望你思考的是基于消费者契约的API测试中对于那些新开发的API或者加了新功能的API由于之前都没有实际的消费者所以你无法通过API Gateway方法得到契约。对于这种情况你会采用什么方法来解决呢
从我的经验来看因为缺乏契约所以还是会采用传统的API测试方法也就是根据API设计文档来设计测试用例。
这时我们采取的API测试策略是
- 对于已经上线的API我们会通过契约测试来保证质量
- 而对于新的API或者是加了新功能的API则还是采用传统的基于API设计文档来设计测试用例同时基于代码覆盖率来指导补充遗漏测试用例的方式来保证质量。当这些新API上线运行了一段时间后我们就会缩小测试的范围逐渐向契约测试过渡。
## 问题四:你所在公司,在进行代码级测试时,采用过哪些方法呢?
在专栏的第25篇文章[《不破不立:掌握代码级测试的基本理念与方法》](https://time.geekbang.org/column/article/14008)中,我根据实际工程项目中的实践,总结了五种常见的代码错误,以及对应的四大类代码级测试方法。这里我还想在多啰嗦一句,代码级测试的测试方法一定是一套测试方法的集合,而不是一个测试方法。
而在这篇文章最后我希望你分享一下你所在公司在进行代码级测试时采用过哪些方法又是如何具体开展的。这里我来分享下我在eBay的经验吧。
在eBay代码质量保障已经完全纳入了CI/CD流水线。
首先我们基于Sonar启用了静态代码。除了在上传Git的时候触发静态扫描外开发人员在本地IDE中也会进行实时的静态扫描并可以实时看到分析结果这样就可以在代码被递交到代码仓库前就已经完成了预检测。
其实,我们并没有直接采用标准的代码静态扫描的规则库,而是删除了其中很多我们认为过于严格的规则,同时加入了一些我们认为比较重要的检测项,使得这个规则库更符合我们的业务场景。一般情况下,这些规则的修订是由测试架构师牵头,与开发主管和资深的开发人员一起协商决定的。
这里需要注意的是我们并不要求静态扫描上报的所有错误都被修复后才能发布只要求解决最关键的问题即可。而对于那些所谓的Code Smell问题基于研发成本的考虑我们并不会要求完全修复。
接着CI/CD流水线会触发代码动态测试即单元测试。这里我们不仅要求单元测试能够100%通过并且会要求达到一定的代码覆盖率。在eBay我们对不同模块的代码覆盖率要求也不一样并没有一个硬性指标。其实这也是出于研发成本的考虑。
通常来讲,对底层模块以及提供公共服务的中间件的代码覆盖率指标的要求,一般都会比较高。而我们对前端模块的覆盖率要求,就会低很多。
## 问题五除了Sonar你还用过哪些静态代码扫描工具使用过程中遇到过哪些问题
在专栏的第26篇文章[《深入浅出之静态测试方法》](https://time.geekbang.org/column/article/14197)中我和你详细分享了人工静态测试方法和自动静态测试方法来帮你理解研发流程上是如何保证代码质量的。另外我以Sonar为例和你分享了如何搭建自己的自动静态代码扫描方案并且应用到项目的日常开发工作中去。
而在这篇文章最后我希望你分享的是除了Sonar你还用过哪些静态代码扫描工具使用过程中遇到过哪些问题。
其实优秀的代码静态扫描工具远远不止Sonar比如Fortify SCA和Checkmarx CxSuite等都是很优秀的静态扫描工具。至于使用过程中需要的问题我觉得主要有这么三个
**第一是误报率**。过高的误报率会降低开发人员对测试工具的信任度,而且还会引入很多人为标注的工作量。
**第二是规则库的完备性和实用性**。很多时候你会发现标准代码规则库中的一些规则设计不够合理有点教条主义。比如有些规则库会强行规定一个函数的代码行数不能超过200行从代码的模块化和易维护性角度来讲过长的函数实现体的确不利于代码健康。但是也不能完全一刀切毕竟有些函数就是实现起来比较复杂。所以很多时候我们需要对标准规则库进行深层次地裁剪以更好地适应企业的实际情况。
**第三是自定义规则的难易程度**。虽然很多静态代码工具都提供了规则编辑器,来方便你实现自己的规则,但是这些规则编辑器的使用方法和语法的学习成本比较高,对初学者不够友好。
## 问题六:在单元测试过程中,你都遇到过哪些问题,又是如何解决的呢?
在专栏的第27篇文章[《深入浅出之动态测试方法》](https://time.geekbang.org/column/article/14344)中,我和你分享了人工动态测试方法和自动动态测试方法。因为自动动态方法并不能理解代码逻辑,所以仅仅被用于发现异常、崩溃和超时这类“有特征”的错误,而对于代码逻辑功能的测试,主要还是要依靠人工动态方法。
在这篇文章最后,我希望你分享的是,除了我在文中提到的几个单元测试的难点问题,你还遇到过哪些问题,又是如何解决的。
这里,我想再和你分享我曾在单元测试中遇到过的问题。
**单元测试的难点中较为典型的就是对内部输入的控制**。对于内部输入的控制有数十种不同的场景,这里我就举一个例子,意在抛砖引玉。
首先为了达到较高的测试代码覆盖率如果代码中包括了if-else分支那么我们的测试就需要分别执行到这两个分支。假设现在有一个if-else分支是根据malloc这个内存分配函数的结果进行不同的处理如果内存分配成功了就执行A逻辑如果执行失败了就执行B逻辑。
那么在做单元测试的时候通常情况下很容易覆盖内存分配成功的场景但是想要实现“可控”的内存分配失败就比较困难了。因为malloc是个底层系统函数根本无法对其控制。
为了解决这个问题我们就可以采用桩函数的思想引入一个malloc的桩函数在这个桩函数的内部再去调用真正的系统malloc函数如果需要模拟真正的malloc函数的失败就在桩函数里面直接返回malloc函数失败的返回值来达到模拟真正malloc函数失败场景的目的。这样就能在被测函数中通过可控的方式来模拟系统底层函数的返回值了。
最后感谢你能认真阅读第22~27这6篇文章的内容并写下了你的想法和问题。期待你能继续关注我的专栏继续留下你对文章内容的思考我也在一直关注着你的留言、你的学习情况。
感谢你的支持,我们下一期答疑文章再见!