5

我了解如何实施单元测试,我只是在努力弄清楚何时使用它们。

假设我有一个基本的提醒应用程序。用户可以添加/编辑/删除提醒并在表格视图中查看它们。我想为应用程序的哪些部分设置单元测试?

4

4 回答 4

6

理想世界的答案会说您编写的每一行代码都应该进行单元测试。

但是让我们暂时忘记这一点,回到现实世界。为重要的代码编写测试并且拥有另一道防线是值得的。换句话说,测试简单地为一个字段赋值的构造函数是否有意义?很可能不是。对从客户提供的复杂 XML 中提取帐户数据的解析器进行单元测试是否值得?大概是。

这种差异从何而来?两个主要原因:

  • 构造函数代码不太可能遭受不可预测的更改(与不断发展的解析器代码相比,以满足不断变化的需求/优化/重构)
  • 构造函数代码相当简单,并且您已经多次编写此类代码,测试可能不会为您提供发现问题的巨大优势;快速浏览一下这样的代码,您很可能会知道发生了什么(与复杂的 XML 解析器代码相比)

为什么要区分?为什么要测试这个而不是那个?简单地测试一切会不会更容易(正如理想世界的答案所暗示的那样)?

不,因为时间和金钱的限制。编写代码需要两者。有人愿意为你的产品支付一定数量的钱,就像他只需要一定的时间等待产品交付一样。有些测试根本不值得(再次,构造函数代码示例)。请记住,单元测试无法避免 收益递减(测试覆盖 80% 的代码库可能需要额外 20% 的开发时间,然后节省 20% 的调试/维护时间,而再进行 10% 的测试可能会花费两倍的时间但收益要少得多)。

再次,您可能想问“线路在哪里?” 你什么时候决定“好的,这段代码的单元测试并不是真的需要”?不幸的是,这种判断来自经验。编写代码,阅读代码,看看其他人(可能更有经验的开发人员)做什么和学习。

如果我要给出几个通用的建议(单元测试的内容),那将是:

  • 从业务/领域逻辑代码开始
  • 确保测试所有类型的转换器/解析器/计算器(它们相当容易测试,往往会经常更改[由于需求变化或重构],并且它们的性质容易出错)
  • 避免测试简单的单行方法,除非那一行在某些方面至关重要
  • 为您发现的错误编写测试(并保留它们!)
  • 不要盲目地遵循“好代码必须有 99.99% 的测试覆盖率”的神奇童话
  • programmers.stackexchange.com上阅读有关 主题的问题通常可以为您提供解决问题的不同视角
于 2012-10-03T19:31:19.593 回答
1

假设您将提醒存储在某个地方,也许在 plist 中。你可以编写一个单元测试来生成一个 Reminder 对象,存储它,检索数据,最后生成一个可用的 Reminder 类对象。

这样你就知道了几件事:

答:您的提醒生成正在工作

B:您存储数据的方法有效

C:从数据转到您的提醒对象正在工作

但是,您不应期望能够对应用程序的实际“功能”进行单元测试。例如触摸事件或导航控件。这些应该留给验收测试,这是一个完全不同的讨论。

于 2012-10-03T19:01:08.753 回答
1

测试您编写的所有代码。如果你想变得很酷,先写测试。如果您在模型或控制器上有一个方法,您还应该对其进行测试。

在不了解您的代码的情况下,很难给出建议。但听起来你会有一个控制器(如RemindersController)和一个模型(如Reminder)。这将是我要开始的基本大纲:

  • 提醒控制器

    • 应该添加一个新的提醒
    • 应该更新现有的提醒
    • 应该删除现有的提醒
  • 提醒

    • initWithMessage:atTime:应该设置一条消息
    • initWithMessage:atTime:应该设定一个时间
于 2012-10-03T19:04:03.663 回答
0

在选择编写什么类型的测试以及何时编写测试时,我遵循以下原则:

  • 专注于编写端到端测试。与单元测试相比,您在每个测试中覆盖的代码更多,因此可以获得更多的测试收益。使这些成为整个系统的基本自动验证。

  • 下降到围绕复杂逻辑块编写单元测试。在端到端测试难以调试或难以编写以获得足够的代码覆盖率的情况下,单元测试是值得的。

  • 等到您正在测试的 API 稳定后,再编写任一类型的测试。您希望避免重构您的实现和测试。

Rob Ashton 有一篇关于这个主题的好文章,我大量引用了这篇文章来阐明上述原则。

于 2013-03-22T13:29:41.507 回答