软件测试中的黑天鹅系列:(一)认识软件测试中的黑天鹅

认识软件测试中的黑天鹅

      邰晓梅

1.       软件测试中的“黑天鹅”

几年前,我带领的一个测试小组遗漏了一个严重的bug到网上,当用户反馈这个bug后,我们对它进行了深入的分析和重现,最终所有人一致认为,这个bug能够发生实在是机缘巧合,因为它需要多个条件同时发生才有可能触发,比如“XX算法开关必须打开、XX算法开关又必须关闭、XX参数必须取某个特定值、用户的使用环境必须是XX个场景、硬件必须是使用XX接口板、软件必须是XX版本、XX的带宽恰巧又不够。。。”,在用户那里,这些条件有一条不满足,就不会发生这个bug。

由于这个bug的影响比较严重,又是用户报告的,照例要提交缺陷根因分析报告。其中,报告里有一项“后续如何发现这类缺陷,确保不遗漏?”我们不知道如何避免这样的缺陷再次发生,实际上,如果从正向设计的角度,我们无论如何也不会设计一个满足上述所有条件的用例,也不会去执行这样的测试。不过,我们不得不费尽心思地去思考,这个bug的发生是如何有其合理性的、是可以解释的、因此也是可以预防的,以填补报告里这一项的空白。

前不久我阅读了一本书叫做《黑天鹅》。数千年来,人们认为世界上只有白天鹅,但是发现第一只澳大利亚黑天鹅以后,这种牢不可破的观念被颠覆了。作者指出“黑天鹅事件”满足三个特征:

-       稀有性,或意外性,即它通常在预期之外;

-       冲击性,即它会产生极端影响;

-       事后(而不是事前)可预测性,人的本性促使我们在事后为它的发生编织理由,并且或多或少地认为它是可解释和可预测的。

很多重要的线上bug不就是测试中的“黑天鹅”吗?它们的发生在你的预期之外、产生了极端的影响、事后人们总是认为这些bug是可以避免的。

仔细想一想,你所在的项目中是否有“黑天鹅”?2013年1月31日,亚马逊主页瘫痪近1小时,你是否提前预期到了(《黑天鹅》书中写到,“从对称的角度讲,一个高度不可能事情的发生,与一个高度可能事件的不发生是一样的”)?12306网站的瘫痪、高铁事故、ATM取款系统故障。。。,你是否能提前预期到?其实,你可能已经发现,“黑天鹅”离我们并不遥远,总是有那么多被认为不应该发生的现象实际发生了。

造成“黑天鹅”现象的可能有很多种原因,从测试的角度讲,我们如何来认识软件测试中的“黑天鹅” – 那些总是让人意想不到又产生严重后果的bug呢?

2.       对“黑天鹅”视而不见

人们习 惯于对“黑天鹅”视而不见。“社会学家一直错误地以为他们的理论能够衡量不确定的事物”。人们相信通过使用趋势分析工具和复杂的数学公式可以帮助我们很好地预测股票市场的风险、挑选一支好的股票,结果大失所望的人不在少数;人们相信复杂的科学仪器和先进的数学、物理学、天文学等理论可以帮助我们很好地预测地震、海啸、天气,结果经常有令人意想不到的自然灾害发生。

人们习惯于使用确定性的理论去推测那些不确定的事物,在这个处处都充满了“变数”的时代,“以不变应万变”的做法已不合适。RBT(基于风险的测试)是个不错的方法,有些人会按照既定的套路使用RBT:在项目的某个时间点,邀请相关人一起收集风险、分析风险,然后按照风险分析结果开展测试活动。但是风险是时刻变化的、风险是不能确定的,你不可能提前预期所有的风险,你得学会“以动制动”,动态地、持续地应用RBT技术。哪怕如此,你仍然无法避免所有的风险,仍然会有“黑天鹅”发生,因为软件测试的过程充满了随机性。

ReqBT(基于需求的测试)是个至少从数学上说很严谨的测试技术,它会用因果图的方法把业务中的每一个原子逻辑规则都表达出来。ReqBT的创始人Richard Bender认为只要使用了ReqBT方法,不会遗漏一个从黑盒角度讲、功能上的、业务逻辑相关的、严重的bug。我深知这套方法的妙处,但仍然对如上的陈述有所怀疑,原因无他,测试中的不确定性太多,没有哪个确定性的理论是银弹,可以保证没有某类的“黑天鹅”发生。

但这并不表示这些形式或模式确定类的技术没有任何用处、只要使用不确定性的技术比如ET(探索性测试)、RST(快速软件测试)等就好了。应该说,这些确定性的方法(RBT、ReqBT等)和不确定性的方法(ET、RST等)结合起来使用的话,“动静结合”,会更有效地减少测试中“黑天鹅”的发生。

3.       判断是否是“黑天鹅”

想知道哪些重要的软件缺陷是“黑天鹅”,哪些不是?只要问一问,这些bug与出现之前所预期的相比较,是否是在预料之中的?

我们会发现,这些重要的bug大体可以分为两类:一类是可以预期发生的,但是并没有采取及时的措施去规避;一类是不被预期发生的,认为不应该发生这种缺陷。这就启发我们在做RCA(缺陷根因分析)时,对不同类bug的分析会带来不同的收获。

分析可以预期发生的严重缺陷,可以很好地帮助我们改进已经在实施的确定类方法或技术中的不足。比如在实施RBT过程中,为什么没有识别出某个风险?或者为什么对风险级别的估计不足?或者为什么没有对已知的风险采取风险规避措施?再比如在应用MBT(基于模型的测试技术)过程中,为什么某一个因子在建模时被遗漏了?或者为什么基于模型生成测试条件或测试用例时某个重要的参数被忽略掉了?再比如按照企业既定的流程管理软件测试的过程中,为什么在测试策略或测试方案中忽略了这一风险?或者为什么在测试分析和测试设计中没有覆盖这个风险点?或者为什么在测试执行环节没有发现这个缺陷?等等。通过这样的RCA过程,可以更好地帮助我们改善既有的测试方法或流程。

分析不被预期发生的严重缺陷,可以为我们开展不确定类测试方法或技术提供更多的输入和想法。例如本文开篇所举的那个关于某算法失效的例子,想通过确定类的测试方法、正向的方式提前设计(也就是预期)相关的测试用例,基本不大可能。相反,我们换一个角度,也许在ET中探索出这个缺陷的几率更大一些,比如适当增加与用户应用环境相关的各种因子组合的复杂场景测试的session。

《黑天鹅》是一本关于不确定性的书。“有两种认识现象的方式。第一种排除不正常的现象,只关注正常现象。研究者不理会意外事件,只研究正常案例。第二种方法则认为,为了理解这一现象,人们需要首先考虑极端现象,尤其是当它们有非同寻常的效应累积的时候,比如黑天鹅现象。”对于测试而言,如果希望了解我们的不足,这两类缺陷(可以被预期的缺陷和不可以被预期的缺陷)都要分析。

4.       我们所不知道的更有意义

“黑天鹅的逻辑是,你不知道的事比你知道的事更有意义,因为许多黑天鹅事件正是由于它们不被预期而发生和加剧的。”作者认为现在的世界由不确定性主导,不论这个结论正确与否,单就测试而言,这个结论是非常适用的,软件测试是由不确定性主导的。测试就是寻找未知的过程,这些未知的事情包括未知的缺陷、未知的被测对象的质量状况、未知的真实的被测对象是什么样的以及所有那些你认为你已经知道的但实际上是你不知道的软件相关的信息,这些未知给予测试挑战的同时也赋予测试很大的意义。

可以这样说,所有的测试用例都是基于测试人员已知的知识设计出来的,执行这些用例有机会发现那些能够被预期的缺陷;而测试中的“黑天鹅”- 那些重要的不被预期的缺陷,有多少是由测试用例发现的?

分析每一只“黑天鹅”,会帮助我们发现那些原本对于我们是“未知”的东西,每一只“黑天鹅”的遗漏,都是由于一些“未知”的因素,或者是未知的知识或信息、或者是不知道某些信息的重要程度而加以重视。下一次测试中,就会有意识地尽量拓宽我们的已知领域,减少“黑天鹅”发生的次数。

探索性测试在拓宽“已知领域”方面功不可没。当我们需要探索时、当我们不知道下一步测试什么时、当我们想要获得更多的想法时,我们使用探索性测试,ET有助于拓宽我们的测试深度和测试宽度,尽可能扩大已知领域的边界,缩小我们未知的领域。

5.       结论

你看到一个后果很严重的缺陷,正是由于你认为它不应该发生?这是不是很奇怪?不管你采用什么样的测试方法、你的测试团队有多么强大、你在测试上投入了多少人力物力,测试中的“黑天鹅”总会发生。

作者在《黑天鹅》书中指出人性的一个弱点:“习惯于学习精确的东西,而不是总体的东西”,并且把“由于只关注那些纯粹而有明确定义的‘形式’而导致的错误”称为‘柏拉图化’”。测试的柏拉图化思想会让你只关注外在的形式,例如测试的流程是否遵守、测试的模板是否应用、测试方法的具体步骤是否实施,而开始忽略其他不那么具体不那么明确不那么美好和解释得清的事务,忽略那些显得有些混乱和不可琢磨的事务,比如在有些人眼里,探索性测试不容易管理、不好解释给别人、步骤不那么明确、有太多不可琢磨的东西在里面。

就像敏捷里承认变化总会存在而去拥抱变化一样,我们也应该正视测试中“黑天鹅”现象的存在,并尽最大可能地多尝试以减少“黑天鹅”发生的机会(拓展已知领域、减少未知领域),并且一旦“黑天鹅”发生了尽最大可能地把握黑天鹅机会(分析那些未知点,更好地应用不确定类的方法,寻求测试改进)。

References

Nassim Nicholas Taleb, The Black Swan: Second Edition: The Impact of the Highly Improbable, 2008

 

 

软件测试中的黑天鹅系列:(一)认识软件测试中的黑天鹅》的评论


  1. bob说:

    这两天刚好也看完了《黑天鹅》,里面有些观点确实比较有新意。其实我一直在想一个问题:为什么市场上写“成功人士”的书籍很多,而几乎很少写“失败人士”的经历。我觉得“成功人士”其实就是一个“黑天鹅”现象。——说了些题外话。
    回到测试。今晚我们组全员还针对上个版本的测试问题进行了总结和反思,以期对下个版本在保证质量方面有改进。有个同事特别提到他遗漏的一个严重问题:需要某个异常场景下,做某个异常操作,还需要某个异常模块时才会出现,而且是必现。其实这已经有点像“黑天鹅”。记得当时这个同事在谈到如何改进时说:真不知道为什么这场景会影响其功能;当时测试分析时,如果我知道硬件上的这个问题与那个异常操作有关,就能避免……正如邰老师所说,也许这个问题的最大教训就是“尽可能扩大已知领域的边界,缩小我们未知的领域”,以求尽最大可能地减少“黑天鹅”发生的机会。

     


  2. 天堂旅人说:

    我觉得可以拿织渔网打个比喻:我们的测试实际上就是在需求中寻找各种测试因子,然后分析每个等价类,再对等价类进行正交分析,最后不同的等价类相互交织,形成一张网。通过这个“网”,我们可以捞上来一些“鱼”,从测试者来说,这样进行的测试设计至少做到了系统化。但是,总有漏网之“鱼”,这些”鱼”也许就是所说的“黑天鹅”吧。
    正交方法作为一种测试方法也许本身能帮助测试者系统的测试,但是,并不是所有人织的网都是能很高效的捕到“鱼”的,渔网密不密不密,有没有撒对地方?这些都是决定着你能否捕捉到更多的鱼。就测试而言,我们的测试因子分析得是否完整,等价类是否分析的全面,测试点是否足够,对于被测对象的状态覆盖程度如何,并发压力异常性能个等等方面是否都考虑,都取决着测试的质量。
    假定测试人员是一个负责的人,那么漏测问题归根结底就是测试人员的认知问题。对内部实现不了解,可能会造成内部异常分支覆盖的遗漏,对运行环境的不了解可能会造成因为外部环境问题导致的系统问题(如因为cache,指令乱序,多核等环境造成的软件功能性能问题),对下游应用不了解造成的的问题(这种情况在HW好像经常有,我们拿到的需求往往是比较简单的描述,通常只能在这些简单的描述中提取测试因子)。
    其实归根结底,我想作为一个基层测试人员我们要做的也就是两件事情:学习和总结,通过学习,不断探索未知的领域,可以把我们的那张“渔网”织的更密,通过总结,我们把自己的“渔网”补得更劳。除此之外,我们还要相信,bug是永远也测不完的,真正的零缺陷是永远达不到的,测试人员不是神,只能尽量争取用最少的时间尽可能测出更多的bug。
    另外,我很赞成小梅姐说的测试的柏拉图化的观点,任何事物都有A面和B面,对于测试来说,我们用形式化的方法织起一个网,并且通过这个网捞起的“鱼”是我们所看到的A面,在水中,很多鱼从网的孔里溜掉,是我们未曾看到的B面。在任何测试流程中不能只定义形式化的东西,而缺少了类似代码检视,发散性测试以及测试工作以外必要的学习。

     


  3. 张说:

    写的不错,持续关注

    将你加到我的博客链接中了

    http://dylan.weblogs.co/

     


  4. tester说:

    如果我们将软件比喻成一片广阔的区域,而且地形复杂,有高山、河流、森林等等,这片区域中有许多目的地,而且对于每个目的地来说,都有数不清的道路可以到达。每条道路上都可能埋藏了威力不一的炸弹。测试人员的责任就是在用户进入这片区域之前,试图将所有道路走一遍,以反馈这片区域到底有多安全,在此过程中一旦踏雷,便通知开发人员排雷。当然测试人员永远不可能将所有道路预先走一遍,一是因为时间成本的限制,二是测试人员不可能知道所有的道路,不过经验丰富的测试人员比新手知道更多的道路,正如生长在一个地形复杂的当地人比游客知道更多通往上山的路,哪怕是一条披满荆棘的羊肠小道。所以测试人员只能优先将用户最可能走的道路走一遍,保证用户进入这片区域后是安全的。

     


    • 邰晓梅说:

      好比喻!
      除了优先将用户最可能走的道路走一遍,还可以结合探索性测试的思路,了解更多测试人员未知的区域;还可以使用usage based testing的方法,在模拟或真实的用户环境下测试,让很多道路上的问题自动暴露出来

       


  5. tester说:

    为了熟悉这片区域,让越来越多的道路由未知变为已知,需要无数测试人员坚持不懈地奋战下去。

     


  6. tester说:

    测试人员除了保障大多数用户的安全之外,也要保障那些喜欢探险、猎奇的用户的安全,因为他们喜欢专走偏僻的,难走的,不为人所知的小道。所以这就需要测试人员应用多种思路,尽可能多的覆盖未知的路。

     

Comment Box is loading comments...