A Survey on Unit Testing Practices and Problems
来自2015年的一篇论文,研究者通过网络在线平台对单元测试相关的问题进行了调查 。主要问了五个问题- RQ1:是什么促使开发人员编写单元测试?
- RQ2:单元测试中的最主要的活动是什么?
- RQ3:开发人员如何编写单元测试?
- RQ4:开发人员如何使用自动化单元测试生成?
- RQ5:单元测试的难点是什么?如何改进单元测试流程?
样本情况
图 2
这一次调查涉及到了全球的225位软件工程师 , 使用不同的语言,分布在29个国家 。
图3
图2和图3显示了这一次调查样本的人口统计数据 。
- 受访者的年龄范围从14岁(AYTM受访者的最低年龄)到72岁 , 其中37%的受访者年龄在25至35岁之间 。
- 尽管也有其他领域的受访者但是大多数受访者在IT领域工作(55.5%) 。
- 最多的受访者(59.06%)来自美国,其次是印度 。总的来说,样本具有一定的全球性来自欧洲(32),北美(143)和南美(13) , 非洲(1),澳大利亚(1)和亚洲(35) 。大多数受访者拥有4年制学位或专业学位 。
样本过滤
在进行调查时,从受访者中获得良好的响应样本可能是一项具有挑战性的任务 。为了更好的得到真实的结果 , 我们对调查者设置了三个资格测试的问题,以确保是他们是真正的软件工程师,并且有开发经验,接触过单元测试 。资格测试的目的不是为了筛选出单元测试专家 。相反 , 我们的调查应该针对所有软件开发人员 , 无论好坏 。然而,我们希望忽略试图欺骗测试系统以收取报酬的潜在受访者 。为此,我们的假设是,任何诚实回答问题的软件开发人员应该能够至少正确分类三个陈述中的两个 。
不到四分之一的受访者(22%)全部正确分类了所有三个陈述;76%至少有两个问题是正确的 , 88%至少有一个问题是正确的 。当然 , 一些给出错误答案的人可能受访者只是不那么有能力;
例如,超过10年编程经验的受访者中有32%全部正确回答,而对于经验不足三年的受访者,这个数字仅为14% 。但是,假设一个真正的软件开发人员阅读问题并正确回答资格测试题而不是随机回答,应该能够至少获得两个正确答案,因此没有或只有一个正确答案的24%的响应是“可疑的” 。虽然看起来资格测试问题(“您是否是软件开发人员?”)在过滤不可靠的响应方面做得相对不错,但我们的结论是这个问题还不够,至少需要回答对两个问题 。因此,我们仅使用76%的数据(即225名受访者中的171名)的数据 。
为了分析受访者的可靠性,我们计算了有序数据的组内相关性(ICC , 使用双向模型和平均值单位以及一致性类型ICC测量) , 以及在调查中使用无名类型问题的Fleiss Kappa(仅针对171个合格的回答) 。对数据进行了数据分析,证明结果是相对比较客观的 。
RQ1: 是什么促使开发人员编写单元测试?
对于第一类问题,调查问卷一共涉及了五个方面的因素,每一个因素分为七个等级,从影响非常大,到几乎没有影响 。图 4
从结果来看开发人员写单元测试的动机主要来源于管理要求和研发人员自己觉得有用两个重要因素 。
RQ2: 单元测试中的主要活动是什么?
针对第二个问题,怎么评估单元测试在整个开发过程中花了多少时间其实是一个非常难的话题,我们没有什么直接的办法,所以将问题拆分成为两部分来综合分析在软件开发过程中,您是如何分配时间的
图5
上图2演示了统计样本中的概率分布图 。这个图显示了结果的最小值、最大值以及四分数数据 。
- 33.04的平均时间用于写新的代码
- 25.32%的时间用于调试
- 17.4%的时间用于写单元测试
尽管从所列出的活动中,编写测试被认为是花费时间最少的,但花费在编写新测试上的时间仍然相当可观,花费在编写新测试上的时间几乎是编写新代码所花费时间的一半 。这让人想起经常引用的估计值 , 即50%的软件开发时间用于测试 。
在编写代码和测试方面 , 这可能并不是真的 , 可以推测需要花更多的时间编写测试 。另一方面,更广泛的术语“测试”将包括处理失败的测试,即调试和修复,从这个意义上说,开发人员认为他们花费了接近一半(42.72%)的时间用于与测试相关的活动 。
值得注意的是,有些人在编写新测试方面花费的时间非常极端;例如,有些受访者花费了更多的时间来进行测试 。这些可能包括那些“测试依赖”的开发人员 。更有趣的是,有21个受访者声称根本不进行测试—占所有(合格)受访者的12%!
我们调查了比较不同开发人员之间是否存在任何趋势,并通过计算中位数和95%置信区间来检查组之间的统计差异 。置信区间是使用1,000次重采样引导计算的[6] 。如果两组的置信区间不重叠,则这两组之间的差异具有统计学意义 。
在编程经验方面,似乎存在一种轻微的趋势 , 随着经验的增加,编写测试的时间减少,但没有显著差异 。然而也可以合理地假设:随着经验的增加,开发人员在编写其测试方面变得更加高效或者更加随意 。考虑到团队规模,似乎存在一种轻微趋势,即在较大的团队中花费更多时间编写测试 。
当一个测试失败了之后,您一般会做什么?
接上一个调查的数据当使用单元测试时,调试和修复所花费的时间(平均开发时间的25.32%+17.40%)受每个失败测试的影响,每个失败测试都需要检查和纠正操作 。
per
Fix the code until the test passes
47.2%
Repair the test to reflect changed behaviour
25.9%
Delete or comment out the failing test or assertion
15.6%
Ignore the failure
11.2%
为了研究这个问题,我们要求受访者估计他们在不同情况下对失败的测试做出反应的频率 , 再以百分比的形式表示 。
图6
上图总结了回答结果:几乎一半的情况下(平均为47.2%) , 开发人员认为单元测试实现了其目的并检测出需要修复的错误 。然而,在52.8%的情况下,他们认为这不是这样,他们要么修复测试,要么根本不处理失败(通过删除或忽略测试) 。这是合理的——在开发过程中 , 功能可能会发生变化,测试需要更新 。根据使用场景不同,单元测试工具并不是“开箱即用”的工具——它们产生需要维护的单元测试 。因此,不同方面的重要性,如可读性和针对代码变更的鲁棒性,非常重要 。
同样,结果在不同人之间是相当一致的 。有超过10年经验的开发人员声称比其他人更经常修复代码,并声称比其他人更不经常忽略或删除失败的测试 。另一方面,经验不足的开发人员声称在修复测试方面比其他经验组花费更多的时间 。值得注意的是 , 经验不足的开发人员(1-3年的经验)比拥有超过10年经验的开发人员更经常删除测试 。
RQ3: 开发人员如何编写单元测试?
前面的研发已经提到,研发人员使用了大约17.4%的时候来写单元测试 。我们现在来确定研发人员是怎么写单元测试的,我们将通过两个问题来确定这个问题研发人员什么情况下会优化单元测试?
将问题分为七个维度,同样以七个等级让受访者回答这个问题 。最赞同的原因是“因为真实场景需求” 。从结果来看 , 并没有体现出明显的差异 。图 7
单元测试的执行速度和单元测试代码重构是开发人员似乎认为不太重要的方面,但总体而言,很难辨别真正的趋势 , 开发人员至少在某种程度上声称他们正在优化他们的测试以满足一切使测试良好的东西 。
当研发人员写测试的时候一般会应用什么技术?
很多人都会说自己使用了系统分析的技术来写单元测试,单元测试覆盖率是在写单元测试过程中也比较重要的技术指标 。这两个看起来是有相关性的,如果使用单元测试覆盖率的工具 , 就意味着有系统性的去提高单元测试覆盖率 。测试驱动开发是第三个研发人员使用得比较多的技术 。图 8
有些令人惊讶的是,近54%的开发人员回答说至少“经常”使用自动化测试生成 。需要注意的是,正如我们从前期研究中看到的 , 自动化测试生成的概念并不是开发人员特别熟悉的,因此,与更常见的技术如代码覆盖率相比 , 开发人员对自动化测试生成的解释不够一致 。显然,这表明从业者需要更好地了解自动化单元测试研究的进展 。然而,在与开发人员的讨论中,有时可以观察到一种对自动化测试生成的不满意 。这个问题的回答似乎表明这并不是普遍的意见 , 开发人员可能比常常被认为的更加开放,愿意接受自动化测试生成 。
变体分析(Mutation Analysis)比其他技术应用得少,但我们认为变体分析是一项高级技术 , 研究人员喜欢并支持它,但不会在实践中被普及使用 。因此,69%的受访者声称至少偶尔使用变体分析的结果令人惊讶:例如 , 变体测试社区的最近研讨会上讨论了为什么实践者没有采用变体分析 。尽管调查结果证实了变体分析并不像代码覆盖率那么常见,但似乎变体分析在实践中比人们所认为的更为常见 。实际上,我们主观地感觉到近年来各种语言的新变体分析工具的增加 , 这可以证实这一趋势 。
RQ3:研发人员声称系统性的写单元测试,同时通过代码覆盖率 。但是并没有统一的标准来定义怎么让一个测试更好
RQ4: 开发人员如何使用自动化单元测试生成?
前面的问题提到研发人员经常使用自动化单元测试工具,这个问题是关于怎么使用自动化单元测试工具的问题 。图 9
上图的统计得出了基本的信息
- 第一,自动化单元测试主要是用来补全手工的单元测试能力 。但是这里面就引出了一些问题 , 自动化单元测试需要被维护,如果错了需要去Debug看是什么原因?自动生成的单元测试代码也需要维护 。自动生成的单元测试可能可读性和可维护性非常低 , 这是一个巨大的挑战 。
- 第二,自动化单元测试一般用来发现崩溃的问题 , 这也是自动化单元测试效果最好的地方 。
然而,随着更先进(和可用)的自动化测试生成工具的出现,这种情况可能会发生变化:自动化测试生成可以作为更好的方法来编写断言或代码 。回归测试也排名较低,这似乎也是有问题的,因为在回归测试中,以前的程序版本通常可以代替规范 , 从而在原则上允许全自动化 。
RQ5: 单元测试的难点是什么?如何改进单元测试流程
最后一个问题是要弄明白写单元测试主要的困难和急需提高的关键点是什么 。编写新的单元测试最困难的是什么
图 10
上图展示了编写新单元测试的困难点是什么,下表总结了Borda排名 。与前面的问题相比,这里的评价者之间的一致性具有更大的置信区间,这表明大家之间的意见不太一致 。
表 2
通过这个统计结果可以发现 。
- 写单元测试最困难的部分在于确定哪些代码是需要进行测试的 。考虑到大部分人写单元测试都会参考单元覆盖率,所以这里面最重要的指导意见就是通过是否覆盖代码来决定哪些代码需要写单元测试 。但是实际上 , 有一些很重要的代码即使覆盖率看起来很好 , 但也需要做更多,更深入的测试 。
- 排名第二的选择是测试中要检查什么 。即使自动化测试生成工具可以解决生成实际测试的问题,但开发者仍然会遇到单元测试需要检查什么的问题 , 开发者也将此问题排名较高 。
- 第三个选择是隔离待测试单元 。确实,这也是自动化单元测试生成的主要挑战之一[7] , 但这个任务很少有工具支持(例如[1],[5]) 。测试生成文献通常忽略了这个方面,因此在这方面有改进软件测试的机会 。这也引发了一个问题 , 即这个问题在多大程度上是由于开发人员编写的代码的可测试性较低(即不良设计)引起的,是否通过改进自动化工具来处理不良代码的方法是正确的?这是值得商榷的 。有趣的是,来自美国的受访者将这个问题排名较低(第4位;排名的差异是显著的),而来自全球的受访者将这个问题排名较高(第2位) 。但是,对于美国受访者,排名前四位的项目总体上更接近 。
如何对报错的测试最难的地方在哪里?
图 11
- 排名第一选项是如果测试容易出现古怪的问题(flaky),即有时失败,有时不失败 。例如,依赖于非确定性代码、环境属性或多线程代码的测试本质上很难调试,因此很难修复 。在某种程度上,古怪测试的问题在于代码,而不是测试,因此与之相关的排名第二的选择是:如果测试代码难以理解,则测试很难修复 。这并不出人意料 , 但从测试生成的角度来看,代码通常必须被视为已知的,只能通过生成的测试实现改进 。但是,确保生成的测试不会出现古怪的问题是一个重要的问题,我们不知道这方面有任何研究工作 。
对单元测试的总体映像
调查的最后一个问题要求受访者指明他们对单元测试的不同说法的认同程度 。图12显示了这些陈述和回答 。对于是否需要更多的工具支持来编写测试,开发人员似乎非常愿意,并渴望看到更多工具 。图 12
有趣的是,人们普遍认为开发人员已经有足够多的测试,尽管仍有相当多的开发人员表示希望拥有更多测试 。
另一方面,认可度最低的是关于开发人员是否真正喜欢编写这些单元测试的问题 。只有大约一半的开发人员感觉写单元测试的体验还行,但这个地方明显需要更多的提高;
提供帮助开发人员的高级工具可能是使测试更加愉快和有成效的一种方式,例如提供自动生成测试的工具 。另一方面 , 前面调查一致,开发人员更认同维护单元测试比编写单元测试更具挑战性 。这对于自动化测试生成工具构成了一个挑战 , 研究仍然非常专注于解决后者的问题,只有少数例外(例如[23]) 。
RQ5: Developers do not seem to enjoy writing tests, and want more tool support—in particular to identify what to test, and how to produce robust tests.
RELATED WORK
虽然有一些针对单元测试的实证结果[17] , 但在软件工程领域,相关的调查频率相对较低,与其他学科如市场营销和心理学相比[16] 。最接近我们调查的是Runeson对单元测试实践的调查[24] 。这项调查提出了50个与单元测试相关的问题,分别是1)什么是单元测试?2)单元测试的优点和缺点 。我们对单元测试的解释与这项调查中得出的解释一致;Runeson的调查中发现的一些弱点也在我们的调查中出现了 。例如,难以确定要测试的单元 , 以及测试维护的难度 。总的来说,我们的调查与Runeson的调查不同之处在于更专注于确定自动单元测试生成可以改进测试的潜在领域 。Torkar和Mankefors[27]对软件重用和测试进行了调查 。这项调查与我们的调查分享了一些见解;例如 , 边界值分析通常由开发人员应用,并且他们的调查还显示,开发人员渴望在编写单元测试时获得更好的工具 。
Geras等人[12]在阿尔伯塔省进行了一项关于测试实践的调查,发现单元测试是最受欢迎的测试方法,但只有30%的测试人员使用了单元测试 。在整个加拿大进行的一项更大的调查[11]证实了单元测试的相对流行 , 并且有越来越多的人对变体分析产生了兴趣,与我们的结果类似 。
Ng等人[21]在他们对澳大利亚软件测试实践的调查中也发现了高度愿意使用自动化工具的意愿,与我们的结果一致 。Lee等人的调查[19]也观察到了支持自动化所需的工具需求 。Causevic等人[2]发现,相对于其他领域(如嵌入式系统),单元测试在Web应用程序中更受欢迎 。与我们的研究相关的是,他们发现开源工具主要用于单元测试,而商业测试工具更多用于更高级别的测试 。Zhao和Elbaum[28]调查了开源项目,发现尽管测试消耗了大量资源,但只有大约一半的项目有基线测试套件 , 只有少数项目使用覆盖分析工具来支持他们的测试 。
总的来说,这些回答指出了自动单元测试生成可以支持开发人员的领域 , 以及需要进一步研究的领域:
CONCLUSIONS
改善软件质量的必要性是被广泛接受的,但问题在于如何实现这一目标 。改进单元测试是其中一种可能性,软件工程研究正在为从业者提供可以提高其测试活动质量和生产力的新技术 。我们的目标是更好地了解单元测试的常规实践 , 以便识别改进的可能性,特别是自动化单元测试生成 。【一个关于单元测试实践的在线调查报告】我们在29个国家共收到了171位参与者的在线调查结果,结果证实单元测试在软件开发过程中扮演了重要角色:开发人员花费了大量时间来编写测试 。显然,还有更多的测试空间:12%的开发人员根本不进行测试,73%的人表示强烈希望拥有更多的测试 。为了加强我们的发现,我们正在探索使用受控实验(例如 , [9]),并计划在未来的工作中使用调查复制和观察方法(例如,工业案例研究) 。
- 开发人员需要帮助来决定要测试什么 , 而不是选择具体的输入值 。自动单元测试的大多数研究都回避了这个问题(例如,通过随机选择或由代码覆盖率驱动选择) 。
- 单元测试需要是现实的:开发人员在编写新测试时,以及在处理失败的测试时 , 最关心的是它们是否是现实的 。一个不现实的情景会使修复测试变得更加困难,开发人员可能不会相信基于不现实的测试修复代码 。
- 单元测试需要是可维护的:即使是自动生成的单元测试,也可能被集成到常规代码库中,在那里它需要像任何其他代码一样手动维护 。如果测试不再反映更新的行为,需要轻松检测到并轻松修复 。
- 单元测试生成最有效的是确定输入值,但未解决的挑战是确定要检查什么 。最终,这意味着长期存在的测试预言问题会像任何其他测试生成方法一样困扰单元测试 , 对此方面的进展将使测试生成工具对从业者更有价值 。