一种特定的测试方法的价值取决于在开发中的系统对任务的关键程度,以及对它的依赖程度。您的网站的简单留言簿脚本几乎不被认为是关键任务,但是如果它运行的网站可能被允许对数据库进行未经过滤的输入的错误所破坏,并且该网站提供了一些重要的服务,那么它突然变得越来越重要了。对于彻底测试留言簿脚本很重要。框架/库代码也是如此。如果您开发的框架带有错误,那么使用该框架功能的每个应用程序也将具有相同的错误。
测试驱动的开发为您提供了额外的安全性。如果您在要测试的代码旁边甚至在测试之后编写测试,则很可能会导致测试错误。如果首先编写所有测试,则代码内部的工作方式不会影响编写测试的目的,因此,不太可能无意中编写了认为特定错误输出正确的测试。
测试驱动的开发还鼓励您的开发人员编写易于测试的代码,因为他们不想给自己做更多的工作!易于测试的代码往往是易于理解,重用和维护的代码。
维护是您真正获得TDD回报的地方。花费在软件上的绝大多数编程工作都与维护相关。这意味着需要更改实时代码,使其具有新功能,修复错误或使其适应新情况。进行此类更改时,您要确保所做的更改具有所需的效果,更重要的是,它们不会产生意想不到的效果。如果您有完整的代码测试套件,那么很容易验证所做的任何更改都不会破坏其他功能,如果所做的更改确实破坏了其他功能,则可以快速找到原因。好处是长期的。
您在问题中说了以下内容:
我看到为某些事情编写测试有一些好处,但很少。尽管我喜欢首先编写测试的想法,但与调试实际代码相比,我发现我花费大量时间尝试调试我的测试,以使他们说出我的意思。这可能是因为测试代码通常比其测试的代码复杂得多。我希望这只是对可用工具(本例中为rspec)的经验不足。
这似乎向我暗示您还没有得到测试。单元测试应该非常简单,只需一系列方法调用,然后是一个断言即可将预期结果与实际结果进行比较。它们之所以简单,是因为测试中的错误是灾难性的,并且如果在测试中引入循环,分支或其他程序抛出控制,则测试中很可能引入了错误。如果您花费大量时间调试测试,则表明您的测试过于复杂,应该简化测试。
如果不能简化测试,那么仅凭这一事实就说明被测代码存在问题。例如,如果您的类的方法很长,具有很多if / elseif / else或switch语句的方法,或者大量的方法具有由类的当前状态决定的复杂的交互,那么测试将必须非常复杂提供完整的代码覆盖范围并测试所有可能性。如果您的班级具有对其他班级的硬编码依赖关系,那么这将再次增加您为了有效测试您的代码而必须跳的步数。
如果您使用较小的方法,很少的执行路径来使类较小且高度集中,并尝试消除内部状态,则可以简化测试。这就是问题的症结所在。好的代码本来就很容易测试。如果代码不容易测试,则可能是有问题。
从长远来看,编写单元测试对您有好处,而避免它们只是在以后存储麻烦。您可能不熟悉技术债务的概念,但是它的工作原理很像金融债务。不编写测试,不注释代码,不编写硬编码的依赖项,等等都是使债务陷入困境的方法。您可以通过尽早地偷工减料来“借”时间,这可能会帮助您按时完成工作,但是您在项目中较早节省的时间却是借来的。每天都在不清理代码,对代码进行正确注释或构建测试套件的情况下,您可能会产生兴趣。持续的时间越长,积累的兴趣就越多。最终,您会发现您的代码变得混乱不堪,如果不触发意外后果就无法进行更改。
您可以考虑及早编写单元测试,并使其保持最新状态,这是“技术信用”的一种形式。您要花时间在银行中,因为要在项目的早期花时间遵循良好的实践。稍后进入项目维护阶段时,您将对这种远见卓识产生兴趣。当您要进行更改时,可以轻松地验证更改的正确性,并且它没有任何有害的副作用,并且您可以迅速获得更新,而不必大惊小怪。如果出现错误,则可以添加一个新的单元测试来执行该错误,然后在代码中修复该错误。下次运行单元测试时,您将能够验证该错误已修复,并且没有引起任何其他问题。此外,您将避免“回归”,
TL:DR-是的,它们是现实世界中的帮助,但它们是投资。好处直到后来才变得明显。