单元测试采用

Bur*_*urt 69 tdd agile automated-tests unit-testing

我们已经尝试将单元测试引入到我们当前的项目中,但它似乎没有起作用.额外的代码似乎已经成为一个维护问题,因为当我们的内部框架发生变化时,我们必须绕过并修复任何挂起它的单元测试.

我们有一个抽象基类,用于单元测试我们的控制器,它作为模板调用子类的抽象方法实现,即Framework调用Initialize,所以我们的控制器类都有自己的Initialize方法.

我曾经是单元测试的倡导者,但它似乎并不适用于我们当前的项目.

任何人都可以帮助确定问题以及我们如何使单元测试对我们而不是对我们有效?

cwa*_*ash 108

提示:

避免编写程序代码

如果它们是针对程序风格的代码编写的,那么测试就可以成为一种保证,这些代码严重依赖于全局状态或者位于丑陋方法的深层.如果您使用OO语言编写代码,请有效地使用OO构造来减少这种情况.

  • 尽可能避免全球状态.
  • 避免静态,因为它们往往会波及你的代码库,并最终导致事物变得不稳定.它们也会破坏您的测试环境(见下文).
  • 有效利用多态性以防止过多的ifs和标志

找出哪些更改,将其封装并将其与保持不变的内容分开.

代码中的阻塞点比其他部分更频繁地改变.在您的代码库中执行此操作,您的测试将变得更加健康.

  • 良好的封装可以实现良好,松散耦合的设计.
  • 重构和模块化.
  • 保持测试小而专注.

测试环境越大,维护就越困难.

尽你所能缩小测试及其执行的周围环境.

  • 使用组合方法重构来测试较小的代码块.
  • 您使用的是较新的测试框架,如TestNG或JUnit4吗?它们允许您通过在测试生命周期中为您提供更细粒度的钩子来消除测试中的重复.
  • 调查使用测试双打(模拟,假货,存根)来减小测试环境的大小.
  • 研究测试数据生成器模式.

从测试中删除重复,但要确保它们保持焦点.

您可能无法删除所有重复项,但仍会尝试将其删除,因为它会导致疼痛.确保你没有删除那么多的重复,以致有人无法进入,并一目了然地告诉测试的内容.(有关同一概念的替代解释,请参阅Paul Wheaton的"邪恶单元测试"一文.)

  • 没有人会想要修复测试,如果他们无法弄清楚它正在做什么.
  • 遵循安排,行为,断言模式.
  • 每次测试只使用一个断言.

在适当的级别测试您要验证的内容.

想想记录和回放Selenium测试所涉及的复杂性,以及在测试单个方法时可能会发生什么变化.

  • 隔离彼此的依赖关系.
  • 使用依赖注入/控制反转.
  • 使用测试双精度初始化对象进行测试,并确保您单独测试单个代码单元.
  • 确保你正在编写相关的测试
    • 通过故意引入错误来"弹出陷阱"并确保它被测试捕获.
  • 另请参见:集成测试是一个骗局

知道何时使用基于状态和基于交互的测试

真正的单元测试需要真正的隔离 单元测试不会打到数据库或打开套接字.停止嘲笑这些互动.验证您是否正确地与协作者交谈,而不是此方法调用的正确结果是"42".

展示测试驾驶规范

讨论一个特定团队是否会采用测试驱动所有代码,或者为每行代码编写"测试优先",这都存在争议.但他们应该先写一些至少一些测试吗?绝对.在某些情况下,测试优先无疑是解决问题的最佳方式.

资源:

  • 说真的,每次测试一个断言?你花了多少时间写测试方法签名? (2认同)

cjk*_*cjk 19

您是否在测试足够小的代码单元?除非您从根本上改变核心代码中的所有内容,否则您不应该看到太多更改.

一旦情况稳定,您将更加欣赏单元测试,但即使是现在您的测试也突出了您的框架变更的传播程度.

这是值得的,尽可能坚持下去.


Mar*_*son 12

如果没有更多信息,很难对你为什么遇到这些问题做出体面的准备.有时,改变界面等不可避免地会破坏很多东西,有时甚至是设计问题.

尝试对您所看到的失败进行分类是个好主意.你有什么问题?例如,由于API更改,它是测试维护(如在重构后编译它们!),还是由于API的行为变化?如果您可以看到模式,那么您可以尝试更改生产代码的设计,或者更好地隔离测试以防止更改.

如果在很多地方改变一些东西会对你的测试套件造成无法估量的破坏,你可以做一些事情(大多数只是常见的单元测试技巧):

  • 开发小的代码单元并测试小的代码单元.在有意义的地方提取接口或基类,以便代码单元中包含"接缝".你必须接受更多的依赖关系(或者更糟糕的是,使用'new'在类中实例化),你的代码将更容易被改变.如果每个代码单元都有一些依赖项(有时是一对或根本没有),那么它最好不要改变.

  • 只能断言测试需要什么.不要在中间,偶然或无关状态下断言.通过合同设计和按合同测试(例如,如果您正在测试堆栈弹出方法,请不要在推送后测试计数属性 - 这应该在单独的测试中).

    我看到这个问题很多,特别是如果每​​个测试都是一个变种.如果任何偶然状态发生变化,它会破坏在其上声明的所有内容(无论是否需要断言).

  • 与普通代码一样,在单元测试中使用工厂和构建器.我学会了一个大约40个测试需要在API更改后更新的构造函数调用...

  • 同样重要的是,首先使用前门.如果可用,您的测试应始终使用正常状态.只有在必要时才使用基于交互的测试(即没有要验证的状态).

无论如何,我的要点是,我试图找出测试破坏的原因/地点并从那里开始.尽力使自己与变化保持隔离.


Jon*_*n B 8

单元测试的一个好处是,当您进行这样的更改时,您可以证明您没有破坏您的代码.你必须让你的测试与你的框架保持同步,但是这个相当平凡的工作比试图弄清楚重构时发生的事情要容易得多.