惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
T
Troy Hunt's Blog
P
Proofpoint News Feed
V
Vulnerabilities – Threatpost
C
Cybersecurity and Infrastructure Security Agency CISA
K
Kaspersky official blog
Cyberwarzone
Cyberwarzone
T
Tor Project blog
Cisco Talos Blog
Cisco Talos Blog
S
Securelist
L
Lohrmann on Cybersecurity
Security Latest
Security Latest
T
Threatpost
H
Heimdal Security Blog
W
WeLiveSecurity
A
Arctic Wolf
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
G
GRAHAM CLULEY
IT之家
IT之家
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
TaoSecurity Blog
TaoSecurity Blog
A
About on SuperTechFans
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
N
News and Events Feed by Topic
Hacker News - Newest:
Hacker News - Newest: "LLM"
Last Week in AI
Last Week in AI
T
The Blog of Author Tim Ferriss
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Microsoft Azure Blog
Microsoft Azure Blog
Hugging Face - Blog
Hugging Face - Blog
Google DeepMind News
Google DeepMind News
量子位
Stack Overflow Blog
Stack Overflow Blog
Know Your Adversary
Know Your Adversary
B
Blog RSS Feed
阮一峰的网络日志
阮一峰的网络日志
WordPress大学
WordPress大学
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
AI
AI
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
博客园 - 司徒正美
Apple Machine Learning Research
Apple Machine Learning Research
GbyAI
GbyAI
Vercel News
Vercel News
C
Cyber Attacks, Cyber Crime and Cyber Security
Latest news
Latest news
D
Darknet – Hacking Tools, Hacker News & Cyber Security
大猫的无限游戏
大猫的无限游戏
Forbes - Security
Forbes - Security

Shidenggui's blog

读《庞居士研究》有感 杂诗 2 杂诗 卢曼卡片盒的本质 致《斯通纳》 古典风格 跳舞吧 无解的问题,有解的人生 杠精是如何炼成的 存在即被承认 混沌宇宙中涌现的秩序 人生革命 少见的艺术家 爱欲之死 世界围绕着心灵旋转 轻信 日常之外的可能性 第二大脑 新品发布:元思笔记 - 打造自生长的知识网络 推书君 APP 上线了!书荒找书,点评分享,尽在其中 如何通过定价充分挖掘隐藏利润? 高不确定性意味着高风险?认知的局限性才是 聪明的学习胜过大量时间的投入 经济机器是如何运行的? 瑜伽不能减肥?我一个月瘦了12斤 从租售比看,北上深的房价为什么不贵? 记一次业务中的算法应用:动态规划、图、树 Jetbrains 福利,半年全家桶或者一年半单产品(PyCharm, WebStorm等)订阅,非激活码,发放到 account BlogHub 上线了,开源独立博客聚合站,一起来发现更多有趣的灵魂 现在还有必要拥有独立博客吗?谈谈我的独立博客史 专属开源开发者的羊毛福利,作者实际到手现金 5K+ (github namebase airdrop) 24 小时开源公益黑客马拉松,开发一款疫情小程序 如何应对软件复杂度 色彩的奥秘 | 设计杂谈(二) 人生第一次翻译英文文章的心得体会 我是如何一步步打造爆款产品,以及对应方法论 | 翻译 设计杂谈(一):什么是美? 读《Elon Musk》:传奇人生之旅的开端(一) 浮生得闲,饭后偶遇桂花树 推书君网站上线了 LRUCache 的实现 复制列表元素时 Python 做了什么 编程与数学(五):Trailing zeroes in factorial 编程与数学(四):Check for integer overflow on multiplication 编程与数学(三):Newton‘s Method 编程与数学(二):Geometric Series 设计模式与 easytrader (一):策略模式 编程与数学(一):Logistic Differential Equation 跑步与数学 Talk is cheap. Show me? 读《Why We Sleep》 读《自控力》 断舍离之公式法 读《师从天才:一个科学王朝的崛起》 读《富足》
读《软件测试的艺术》
2018-03-28 · via Shidenggui's blog

读《软件测试的艺术》

缘起

看完了《富足》之后继续在公司的书架上淘书,偶然看到了一本薄薄的小书《软件测试的艺术》,英文名是 《The Art of Software Testing》。本书出版于 1979 年,距今已经快 40 年了,我手里拿的是第三版。粗粗翻了下,虽然书很久远,但还是有一些挺有意思的观点,所以花了几天时间把它读完了。

我一开始编程完全不知道有测试的概念,后面了解到 TDD,在项目中实践了下,但是有感于测试用例编写的繁琐,最后又废弛了。后面慢慢的又开始写测试了,因为高效的编程离不开测试。测试可以解放我们的大脑,专注于面向接口编程而不需要记住所有接口的内部逻辑,更不要说随之而来的减少 Bug,方便重构等好处了。

概览

整体书主要内容分为二部分。首先是软件测试的心理学,如果你不是从心底认为测试是一个好东西,又怎么能真正重视测试呢。然后是测试的方法论,讲解如何高效的编写测试用例。

正文

因为对测试我本身就怀有很多的疑惑,所以这里以问答的形式总结本书的内容和给我已启发的地方

什么是测试

我:为了保证我们编写的代码正常运行而实行的校验措施,提高我对程序能实现预期功能并在生产环境正常运行的信心。

作者:软件测试是为了发现程序错误而执行程序的过程,是为了增强软件的可靠性。


评论:我以前对测试的态度是消极的,对我编写的代码块来说,我一般认为它是能正常运行的,或者说它大概率能实现我的所思所想,而我写测试只是为了对这个大概率正常的代码进行进一步的验证,可能我多花了一半的时间,但是只剔除了小概率会失败的情况。而作者正好相反,他预期我们的代码大概率蕴含错误,而我们多花一半的时间,剔除了大概率会失败的情况,由此测试的价值大大增加。自然我们内心也有了更强的动力去写测试,毕竟谁不喜欢投入低,产出高的事情呢?

以简单的数学论的话:

假设正常完成的代码块的价值为 1,我投入 10 个单位时间完成功能代码的编写,如果有 90% 的概率能正常运行,此时代码价值为 10 * 0.9 = 9,编码单位时间价值为 0.9 / 10 = 0.09,此时投入 5 个单位时间编写测试,确保剩下的 0.1 个单位的软件价值,则测试单位时间的价值为 0.1 / 5 = 0.02,如果投入 2 个单位时间进行测试,则价值为 0.1 / 2 = 0.05,编程效率分别是之前的 22.22% 、 55.55%。我想任何一个对效率有所的追求的人都很难满意,更不要说跟创造带来的愉悦感相比,测试的编写是个相对无聊的过程。

而作者假设投入 10 个单位时间完成编写过程后,编写的代码只有 50 % 的概率能正常运行,此时代码价值为 10 * 0.5 = 5,单位时间价值为 0.5 / 10 = 0.05。如果我投入 5 个单位时间编写测试,确保了剩下的 0.5 个单位的软件价值,则编写测试单位时间的价值为 0.5 / 5 = 0.1,如果投入 2 个单位时间进行测试,则测试单位时间价值为 0.5 / 2 = 0.25,编程效率为之前的 100% 、 250%。

总结成公式的话,假设 p 为先验代码正确率,Vt / Vc 为测试/编码价值之比,t / c 为测试时间/编码时间, 则公式如下

先验证代码正确率读测试代码价值的影响之对应数学公式

转化成图表如下:

先验证代码正确率读测试代码价值的影响

可见测试的代码价值随着我们对代码正确率信心的下降而指数级上升。在这个复杂的现实世界中,懒惰而又讲究效率的程序员反而会成为测试的坚定拥护者。

为什么我们要写测试

主要有三方面:

一、编写测试可以保证代码实现了我们需要的逻辑,不至于到线上才出现一些低级 Bug。

二、测试可以快速重复多次运行,节省我们每次修改完代码后花费无聊、痛苦的手动测试时间。

三、写测试的过程可以理清我们代码的逻辑,毕竟你不能对一个你自己都不了解要做什么的代码块编写测试。

作者: 软件的运行应当是可预期、稳定的,符合最小惊异原则,软件测试是实现这一目标的手段。据统计分析,每千行代码一般蕴含 1-25 个错误,而测试的目的就是为了找出相关错误。

什么是成功的测试?

我: 没有发现错误的测试就是成功的测试

作者: 发现错误的测试才是成功的测试。类比于对病人做检查,正确查出病因的检查才可称为成功或者有效,测试同样如此。


这里作者提到一个挺有意思的心理学原理,当人知道自己的目标无法达成或者自认为无法实现时,表现会非常糟糕。

为什么测试往往难以落实到实践中

我:

一、测试用例编写编写不当,很多时候对的逻辑可能只有一条,但是错的逻辑有千千条,一开始投入编写测试用例的时间会降低增加软件开发的效率,而无法高效的编写测试用例也会导致对测试心生厌烦。

二、一开始没考虑到模块化、测试的需求,导致后期无法高效的 mock 数据,测试成本过高。

三、测试没有集成到开发流程中,导致有时候测试被破坏没有修复,根据破窗效应,后面的废弛也是预料之中了。

作者:在复杂的现实中,对软件进行完全的测试貌似是不可能的任务,但是我们可以通过相关的方法和技巧提高测试的效率,以达到可以享有测试的大部分好处而不至于投入过多的时间。

而如何高效的测试也是我最有兴趣把本书看完的动力

测试的方法论

测试的几个原则

以下是我感觉比较有意思的

  • 通过有限的测试用例,尽可能多的发现错误:如何更有技巧的编写测试用例
  • 测试需要多次重用:持久化测试用例的价值
  • 程序某部分已发现的错误跟其未发现的错误成正比:如何分配测试用例的精细度
  • 需要对无效输入进行测试:防御性编程

白盒测试

条件/判定覆盖

书里面提到的覆盖条件计算比较复杂,可以用《代码大全》里面提到的简化版来决定测试用例数

  1. 默认测试用例为 1
  2. 遇到 if / else / for / while 等条件语句,测试用例数加 1

黑盒测试

等价类划分

尽量将输入范围划分为几个等价类,使得对某个等价类元素的测试等同于对整个集合的测试。同时区分有效等价类和无效等价类。如果可能的话对输出范围也进行等价类划分。

边界值测试

测试用例的选取尽量选择边界值。边界值一般为上边界、上边界 + 1、下边界、下边界 - 1

错误猜测

尽量选取一些容易导致出错的特殊值,比如 0、None、空数组等等。这个更加依赖于程序员的经验和对编写代码的理解。

因果图分析

这个方法我没看懂,有理解的欢迎在下面回复。具体好像是利用了一些数理逻辑的方式进行了非常复杂的逻辑推断最后得出如何编写对应的测试用例。

测试的编写

以下面这个小函数为例

def double_if_less_than_ten(num):
  if num < 10:
    return num * 2
  return num
  1. 条件/判定覆盖:默认为 1,遇到一个 if 加 1,最后需要至少 2 个测试用例
  2. 等价类划分:有效等价类为 (num < 10) 以及 (num >= 10),无效等价类为 (num 不为数字)
  3. 边界值测试: 上边界相关临界值可取 9, 10
  4. 错误猜测: num 可取 0

综合以上的条件,便可选取尽量少的测试用例覆盖尽量大的测试范围。

numexpected_value满足条件
918if 为 True(num < 10)边界值为 9
1020if 为 False(num >= 10)边界值为 10
00错误猜测 0
Noneraise TypeError无效等价类 (num 不为数字)

尾声

《代码大全》里面提到,越好的程序员越是谦虚,因为他们明白编程是为了弥补人有限的智力,因此愿意通过学习来弥补。而编程糟糕的程序员往往自负,为此失去了提升自我的机会。对测试而言,我觉得下面这句话总结的很好,以此自勉。

Form is liberating