我已经开始阅读@L_403_0@单元测试(因为一位同事手头上有),其开篇章节讨论了为什么要进行单元测试.其中一点是,从长远来看,您的代码更可靠,更清晰,更不容易出错.它还指出,有效的单元测试将使跟踪和修复错误变得更加容易.所以它似乎关注于整体预防/减少代码中的错误.
另一方面,我还发现an article关于编写出色的单元测试,并指出单元测试的目标是使您的设计更加健壮,相反,发现错误是手动测试的目标,而不是单元测试.
因此,作为TDD的新手,我对于我应该进入TDD并构建单元测试的心态感到有些困惑.我承认,我现在使用我最近开始的项目的部分原因是因为我厌倦了我的更改破坏了以前的现有代码.诚然,上面的链接文章至少指出这是TDD的一个优势.但我希望通过回到现有代码中添加单元测试(然后从这一点继续TDD)来帮助防止这些错误.
这本书和本文是否真的用不同的语气说同样的话,或者在这个主题上有一些主观性,而我所看到的只是两个人对如何处理TDD有不同的看法?
提前致谢.
单元测试应该在一些非常小的单元中测试一些执行路径.此单元通常是公共方法或在对象上公开的内部方法.该方法本身仍然可以使用来自同一对象实例的许多其他受保护或私有方法.您可以使用单个方法和多个单元测试此方法来测试不同的执行路径. (通过执行路径,我的意思是由if,switch等控制的东西.)以这种方式编写单元测试将验证您的代码是否真的符合您的期望.这在某些极端情况下尤其重要,在这些情况下,您希望在某些罕见的情况下抛出异常等.您还可以测试方法在传递不同参数时的行为方式 – 例如null而不是对象实例,用于索引的整数的负值,这对公共API特别有用.
现在假设您测试的方法也使用其他类的实例.怎么处理呢?您是否仍应测试您的单一方法并认为该课程有效?如果课程尚未实施怎么办?如果类内部有一些复杂的逻辑怎么办?您是否应该在当前方法上测试这些执行路径?有两种方法可以解决这个问题:
>在某些情况下,您只需让真实的类实例与您的方法一起进行测试.例如,这在日志记录的情况下非常常见(也可以将日志用于测试).
>对于其他场景,您希望从您的方法中获取此依赖项,但如何执行此操作?解决方案是依赖注入和实现反对抽象而不是实现.这是什么意思?这意味着您的方法/类不会创建这些依赖项的实例,而是通过方法参数,类构造函数或类属性来获取它们.它还意味着您不会期望具体实现,而是抽象基类或接口.这将允许您将伪造,虚拟或模拟实现传递给测试对象.这些特殊类型的实现根本不进行任何处理,它们获取一些数据并返回预期结果.这将允许您无依赖地测试您的方法,并导致更好,更可扩展的设计.
有什么缺点?一旦你开始使用fakes / mocks你正在测试单个方法/类,但你没有一个测试会抓住所有真正的实现并将它们放在一起测试整个系统是否真的有效=你可以有数千个单元测试并验证你的每个方法都有效但并不意味着它们会一起工作.这是更复杂测试的场景 – 集成或端到端测试.
单元测试通常应该很容易编写 – 如果不是这意味着你的设计可能很复杂,你应该考虑重构.它们也应该非常快速地执行,因此您可以经常运行它们.其他类型的测试可能更复杂,也很慢,它们应该主要在构建服务器上运行.
它如何适应软件开发过程?开发过程中最糟糕的部分是稳定和错误修复,因为这部分很难估计.为了能够估计bug修复的时间,你必须知道导致bug的原因.但这项调查无法估计.您可能有一个小时需要修复的错误,但您将花费两周时间调试应用程序并搜索此错误.使用良好的代码覆盖时,您很可能会在开发过程中尽早发现此类错误.
自动测试并不是说SW不包含错误.它只是说你在开发过程中尽力找到并解决它们,因此你的稳定性可能会更少痛苦,也更短.它也没有说你的SW做了它应该做的事情 – 更多的是关于应用程序逻辑本身,必须通过每个用例/用户故事的一些单独测试来测试 – 验收测试(它们也可以自动化).
这如何适合TDD? TDD将其推向极致,因为在TDD中,您将首先编写测试以提高质量,代码覆盖率和设计.