何时使用unit testing?
我明白如何实现unit testing,我只是在努力弄清楚什么时候使用它们。
假设我有一个基本的提醒应用程序。 用户可以添加/编辑/删除提醒,并在桌面视图中查看。 我想要设置unit testing的哪些部分的应用程序?
理想的世界答案会说,你写的每一行代码应该是unit testing。
但是让我们暂且忘记,回到现实世界 。 编写testing代码是重要的,有另一道防线是值得的。 换句话说,testing构造函数是否很简单,只需将值分配给一个字段? 很可能不是。 unit testingparsing器是否值得从客户端提供的复杂XML中提取帐户数据? 可能是。
这种差异从哪里来? 两个主要原因:
- 构造函数代码不太可能会遭受不可预测的变化(相对于不断变化的parsing器代码来满足不断变化的需求/优化/重构)
- 构造函数的代码是相当简单的,你已经写了很多次这样的代码,testing可能不会提供你在发现问题的巨大优势; 快速浏览一下这样的代码,你很可能会知道发生了什么事情(而不是复杂的XMLparsing器代码)
为什么要区分? 为什么要testing这个而不是那个? 简单地testing一切( 理想的世界答案会提示)不是更简单吗?
不是。由于时间和金钱的限制。 编写代码需要两个 。 只有一定数量的人愿意为你的产品付钱,就像他只有一定的时间等待交付。 一些testing是不值得的(再次,构造函数代码示例)。 请记住,unit testing对于收益递减是不可避免的 (testing覆盖80%的代码可能需要额外的20%的开发时间,并且以后可以节省20%的debugging/维护时间,而另外10%的时间可能耗时两倍但收益较小)。
再一次,你可能想问“在哪里?” 你什么时候决定“好的,这段代码的unit testing不是真的需要” ? 不幸的是,这种判断来自经验。 编写代码,阅读代码,看看其他人(可能是更有经验的开发人员)做和学习。
如果我要给几个通用的build议( unit testing ),那将是:
- 从业务/域逻辑代码开始
- 确保testing所有types的转换器/parsing器/计算器(这些testing相当容易,往往会经常改变(或者由于需求或者重构的改变),而且本质上是容易出错的)
- 避免testing简单的单线程方法,除非这一行在某种程度上是至关重要的
- 写testing你发现的错误(并保持它们!)
- 盲目追求“好代码必须有99.99%的testing覆盖率”的魔法童话
- 在程序员阅读有关主题的 问题 .stackexchange.com经常会给你不同的观点来解决问题
testing你写的所有代码。 如果你想变得很酷, 请先写testing 。 如果你在模型或控制器上有一个方法,你也应该有一个testing。
不知道更多关于你的代码,很难提供build议。 但听起来像你会有一个控制器(如RemindersController
)和一个模型(如Reminder
)。 这将是一个基本的概述,我将开始:
-
RemindersController
- 应该添加一个新的提醒
- 应该更新现有的提醒
- 应该删除一个现有的提醒
-
提醒
-
initWithMessage:atTime:
应该设置一个消息 -
initWithMessage:atTime:
应该设置一个时间
-
假设你在某处存储提醒,也许在plist中。 你可以编写一个unit testing来生成一个Reminder对象,存储它,检索数据,最后生成一个可用的Reminder类对象。
这样你就知道几件事情:
答:您的提醒一代正在工作
B:你存储数据的方法正在工作
C:从数据到您的提醒对象正在工作
但是,你不应该期望能够unit testing你的应用程序的实际“function”。 如触摸事件或导航控件。 这些应该留给验收testing,这是一个完全不同的讨论。
我遵循这些原则来select要写什么types的testing以及何时:
-
专注于编写端到端的testing。 与unit testing相比,每个testing的代码覆盖更多,因此获得更多testing的代价是巨大的。 将这些作为一个整体对系统进行面包和黄油自动validation。
-
下降到编写复杂逻辑块的unit testing。 在端到端testing难以debugging或难以编写足够的代码覆盖的情况下,unit testing是值得的。
-
等到你正在testing的API是稳定的写任何一种types的testing。 你想避免重构你的实现和你的testing。
罗伯·阿什顿(Rob Ashton)在这个话题上有一篇很好的文章 ,我从中吸取了大量的精力来阐述上述原则。