太长不读版:
软件测试(Software Testing)= 检验 (Checking)+ 测试(Testing)
It should be Testing AND Checking instead of Testing VS Checking.
正文:
看到标题你也许会在暗自翻白眼,不同的角色可能有不同的想法:
A:“我一个N年老QA还不会测试吗?”(N>5)
B:“测试这么没有门槛的事情,比写Bug难吗?”
C:“我只写卡,测试关我什么事。”
D:“我不需要会测,我知道怎么让人测就行了。”
E:“不关心怎么测,能测完就行。”
如果你有以上类似想法,就不难理解为什么我们会在质量工作中听到如下言论了:
A:“你不应该这么测,应该那么测。”
B:“Bug Bash没意思,不想做。”
C:“测试是QA的事情,不在我考虑范围内。”
D:“哎这个功能不需要给你讲上下文,你就随便测测,我们发Hotfix上了它。”
E:“啥?出事了?这个QA拖出去祭旗。”(只有这条是编的,但不难遇到此情此景)
不了解什么是测试,就可能问出“测试灵魂三问”这么有话题性的问题。对测试的误解不利于各角色之间的有效沟通合作,更不利于团队的质量内建。所以本文我们来聊聊到底什么是测试,个人看法,欢迎探讨。
本文主旨:软件测试(Software Testing)= 检验 (Checking)+ 测试(Testing)。
检验(Checking)是什么?
“Checking is the process of making evaluations by applying algorithmic decision rules to specific observations of a product.”
检验是用算法规则来评估产品的特定观察点(即测试用例)的过程。
检验是证实 Confirmation、验证 Verification 和确认 Validation。
这三个词义相近的单词表达了不同的含义。我们先说验证 Verification,它表示在做一件事时,不确定做的对不对,我们验证自己是不是在做正确的事情(Do the Right Thing);再来说确认 Validation,它表示我们已经知道自己在做正确的事情了,但不确定是不是以一种正确合理的方式在做,所以我们确认的是我们是不是正确的在做事(Do the Thing Right)。由上面的解释可以看出,验证应发生在确认前,我们应该先验证是不是找到了正确的问题,是不是找到了恰当的解决方案,然后再在实施阶段确认我们是不是在以正确的方式去实现它。
在测试工作中,验证可以是需求澄清,在实现需求前先验证需求是否合理有效,以及我们是否在做正确的(用户期望的)需求。验证也可以是策略先行,只有遵循合适的测试策略才能得到期望的测试结果。总之,我们在做事情前先理顺思路,找到真正的问题所在,才有可能合理有效的解决问题。这样就能避免上演“图纸拿倒了,让挖井造了个烟囱”的悲剧。
再来说证实 Confirmation。这个词与前两个词的不同点在于,它强调的是动态的去验证和确认的过程,可以这么理解:
We confirm that we do the right thing via Verification.
We confirm that we do the thing right via Validation.
总结一下,Checking 有丰富的内涵,它需要我们通过一组动态的过程,先验证是不是在做正确的事,再确认是不是在正确的做事。既强调了我们需要做两件事,又强调了这两件事的先后顺序。
检验(Checking)做什么?
自动化测试是 Checking,它帮助我们了解产品是否在预期内工作。无论是开发人员写的单元测试、集成测试,还是测试人员编写的UI自动化或接口自动化测试,只要是基于脚本自动运行的测试,我们都认为是一种 Checking。优秀的程序员会写充分的测试来验证自己的代码,而测试人员也会写大量的自动化测试来减少回归量。
人工执行测试用例也是 Checking,因为测试用例就是一种测试脚本,测试人员根据预先定义好的脚本来执行用例,比对实际结果和预期结果,得出用例通过还是不通过的结论。其实不论是自动化还是人工执行的测试用例,只要结论是 Pass or Fail,都属于 Checking 的范畴。
由于 Checking 是脚本化的,我们是在明确软件预期行为后编写的测试脚本,所以需要一个能够描述软件行为的规范(需求文档或用户故事)。
关于 Checking 值得一提的是,Checking 的测试全部通过并不意味着软件正常工作,存在严重问题也能通过检验。同理,就像我们不可能全量测试一样,Checking 的测试数量再大也不能说明测试是充分的。可能你测了很多都没问题,但问题就出在你没覆盖的那条路径上。尤其做上线前的回归特有感触,一旦你潜意识里想:“这里不用测了,肯定没问题”,上线这里准出事,简直让人怀疑这Bug是不是猴子请来的监工,看看QA在哪里倦怠了,给他点颜色看看。我们戏称之为“测试的墨菲定律”或“测试的测不准原理”。也是基于同样的原因,测试是不可能给出一个“软件质量完全OK”的结论或保证的,只能说“在我们所了解到的范围内,测试全部通过”。如果有QA对质量的断言过于绝对,可以归为江湖骗子一类,玩笑除外。
测试(Testing)是什么?
“Testing is the process of evaluating a product by learning about it through experiencing, exploring, and experimenting, which includes to some degree: questioning, study, modeling, observation, inference, etc.”
测试是通过体验、探索和实验等学习方式来评估产品的过程,它包括不同等级:质疑,学习,建模,观察,推断等等。
测试的目的是为了发现问题,测试过程中的任何疑问都是可探索的对象,问题驱动的测试探索活动有助于更快的发现深层缺陷。测试时,我们学习被测软件的业务流程,研究不同场景的相互影响,了解软件系统的限制条件和外部依赖。只有围绕被测软件进行更深入的学习和探索,才能发现漏测的问题和更多新的信息。
测试是一个发现和探索的过程,通过发现更多软件信息,察觉出可能不为人知的关联,从而更好的评估软件质量。
我们来聊一下发现 Discovery 和探索 Exploration 的区别。发现强调已经找到了结果,而探索强调找寻的过程。
Discover is when you find something.
Explore is when you are looking for something.
E.g. While exploring the mountains we discovered a river!
所以,测试一方面在于找寻的过程,“路漫漫其修远兮,吾将上下而求索”。另一方面在于找到有价值的结果也需要分析和沉淀。有趣的是,有时候甚至都不一定有结果,可能我们测了很多,但一无所获。在这种情况下,我们收获了对质量的信心。“我都这么变态了还没发现问题,看来质量问题不大”,是不是很开心。由于测试不一定有结果,所以我们在测试的时候需要注意,虽然它是一个强调发散的过程,但一定要记得收敛。不要做那个跑不回来的人,迷失在茫茫细节中无法自拔。
测试(Testing)做什么?
在前文中我们可以看出,在测试人员的日常工作中:编写自动化测试脚本、跑测试、手动执行测试用例……类似这种测试工作,可以归于Checking范畴。而除此之外,还有一些测试活动,没有明显的计划性,更依赖于测试人员的知识和经验,一般是随机性较大的对软件进行探索和学习,这类测试活动我们归为Testing范畴。
测试发现的问题可以创建检验预防以后再次发生。比如在聊测试金字塔时,我们强调的原则之一是:“如果一个更高层级的测试发现了一个错误,并且底层测试全都通过了,那么应该写一个低层级测试去覆盖这个错误”。可以看出,测试处于测试金字塔的上层,侧重于学习和探索,更强调测试人员的主观能动性。由于测试可以用于给检验查缺补漏,所以它可以确认检验是否充分。
测试更强调学习和探索,所以即使没有需求文档作依据,也可以开展测试。但需要澄清的是,测试并不是漫无目的的探索,相反的,测试需要带着问题去洞察。
上小节说到,测试是探索和发现,探索的过程是一定的,而发现的结果却是不确定的,所以测试活动会有开放性的结果。喜欢追求标准答案的小伙伴们可能要失望了,测试过程一如我们的人生,但行好事,莫问前程。
总结
基于以上的讨论,我们认为软件测试活动应同时包含测试和检测。在测试策略的演进过程中,自动化测试会把QA从大量重复的Checking类测试中解放出来,从而使大家有时间和精力去进行更能发挥主观能动性的、更有价值的测试活动。而这一部分正是测试过程中“人”存在的意义。
思考题
这两者分别解决了什么问题?
为什么需要明确两者区别?
关于“去测试化”,你怎么看?
后记与参考
第一次听到这个理论来自同事安辉的分享,很受启发,实名感谢。此文是以下两篇文章的读后感和碎碎念,近期一定要翻译一遍并通读所有comments,为了避免“然后就没有然后了”,在此立flag为证。这两篇文章也推荐给大家,读罢让人更能明确“人”的价值将永远不能被机器所取代。
Testing and Checking Refined:https://www.satisfice.com/blog/archives/856
Testing and Checking:https://www.developsense.com/blog/2009/08/testing-vs-checking