虽然,我完全赞成单元测试,但我有时想知道这种形式的测试优先开发是否真的有益......
像这样的小型、琐碎的测试可以成为您代码库的“煤矿中的金丝雀”,在为时已晚之前警告危险。琐碎的测试对于保留是有用的,因为它们可以帮助您正确进行交互。
例如,考虑一个简单的测试来探究如何使用您不熟悉的 API。如果该测试与您在“真正”使用 API 的代码中所做的事情有任何相关性,那么保留该测试很有用。当 API 发布新版本并且您需要升级时。现在,您对 API 的行为方式有了自己的假设,以可执行格式记录下来,您可以使用该格式来捕获回归。
...[I] 在实际过程中,您的代码上方有 3-4 层(业务请求、需求文档、架构文档),其中实际定义的业务规则(折扣价格是价格 - 折扣)可能被错误定义。如果是这种情况,那么您的单元测试对您来说毫无意义。
如果您多年来一直在编写代码而没有编写测试,那么您可能不会立即意识到有任何价值。但是,如果您认为最好的工作方式是“尽早发布、经常发布”或“敏捷”,因为您希望能够快速/持续地部署,那么您的测试肯定是有意义的。做到这一点的唯一方法是通过测试使您对代码所做的每一次更改都合法化。无论测试多么小,一旦您拥有一个绿色测试套件,理论上您就可以部署。另见“持续生产”和“永久测试版”。
您也不必“先测试”才能拥有这种心态,但这通常是实现目标的最有效方式。当您进行 TDD 时,您会将自己锁定在 2 到 3 分钟的小红绿重构周期中。在任何时候,您都不能停下来离开,手上会弄得一团糟,这需要一个小时才能调试并重新组装起来。
此外,您的单元测试是另一个失败点......
成功的测试是证明系统出现故障的测试。失败的测试会提醒您测试逻辑或系统逻辑中的错误。您的测试目标是破坏您的代码或证明一种方案有效。
如果您在代码之后编写测试,您将冒着编写“坏”测试的风险,因为为了看到您的测试真正有效,您需要看到它既损坏又有效。当您在代码之后编写测试时,这意味着您必须“跳出陷阱”并在代码中引入错误以查看测试失败。大多数开发人员不仅对此感到不安,而且认为这是浪费时间。
我们在这里得到什么?
以这种方式做事肯定有好处。Michael Feathers 将“遗留代码”定义为“未经测试的代码”。当您采用这种方法时,您对代码库所做的每一次更改都是合法的。它比不使用测试更严格,但是在维护大型代码库时,它会为自己付出代价。
说到 Feathers,您应该查看两个很好的资源:
这两者都解释了如何将这些类型的实践和学科应用到非“绿地”项目中。它们提供了围绕紧密耦合的组件、硬连线依赖以及您不一定可以控制的事物编写测试的技术。这一切都是为了找到“接缝”并围绕这些进行测试。
[I]如果折扣价格错误,测试团队仍然会发现问题,单元测试如何节省任何工作?
像这样的习惯就像是一种投资。退货不是即时的;它们随着时间的推移而积累。不测试的替代方法本质上是承担无法捕捉回归、引入代码而不用担心集成错误或驱动设计决策的债务。美妙之处在于您将引入代码库的每一个更改都合法化。
我在这里想念什么?请教我热爱 TDD,因为到目前为止我很难接受它是有用的。我也想,因为我想保持进步,但这对我来说没有意义。
我认为这是一种职业责任。是一个为之奋斗的理想。但这非常难以理解和乏味。如果您关心它,并且觉得您不应该编写未经测试的代码,您将能够找到学习良好测试习惯的意志力。我现在(和其他人一样)经常做的一件事是给自己一个小时的时间来编写代码,而无需任何测试,然后有纪律地扔掉它。这可能看起来很浪费,但事实并非如此。这不像锻炼会花费公司的物质材料。它帮助我理解了问题以及如何以更高质量和可测试的方式编写代码。
我的建议最终是,如果你真的不想擅长它,那就不要去做。没有维护的糟糕测试,表现不佳等可能比没有任何测试更糟糕。自己学习很难,你可能不会喜欢它,但如果你没有学习的欲望,或者看不到它的足够价值,那么它几乎是不可能学习的。保证时间投入。
有几个人一直提到测试有助于执行规范。根据我的经验,规范也有错误,而且往往不是......
开发人员的键盘是橡胶与道路相遇的地方。如果规范是错误的并且你没有在上面举起旗帜,那么你很可能会因此受到指责。或者至少你的代码会。测试中涉及的纪律和严格性很难遵守。这一点都不容易。这需要练习、大量学习和大量错误。但最终它确实得到了回报。在一个快节奏、快速变化的项目中,这是你晚上睡觉的唯一方法,不管它是否会让你慢下来。
这里要考虑的另一件事是,与测试基本相同的技术在过去已被证明是有效的:“洁净室”和“按合同设计”都倾向于产生相同类型的“元”代码结构测试做,并在不同的点强制执行。这些技术都不是灵丹妙药,严格要求最终会在您可以交付的功能范围内花费您的产品上市时间。但这不是它的目的。这是关于能够维持你所交付的东西。这对于大多数项目来说非常重要。