【问题标题】:Code reuse in automated acceptance tests without excessive abstraction自动化验收测试中的代码重用,无需过多抽象
【发布时间】:2020-06-02 13:46:21
【问题描述】:

我最近被聘为我工作团队的一员,该团队的重点是为我们公司的 3D 建模软件编写验收测试套件。我们使用内部 C# 框架来编写和运行它们,这基本上相当于继承 TestBase 类并覆盖 Test() 方法,通常所有设置、测试和拆卸都在此完成。

在编写测试时,我注意到我的很多代码最终都是我经常重写的样板代码。我一直有兴趣尝试提取该代码以使其可重用并使我的代码更干燥,但我一直在努力寻找一种方法来做到这一点,而不会过度抽象我的测试,而这些测试应该基本上是独立的。我尝试了多种方法,但都遇到了问题:

  1. 使用继承: 最简单的解决方案,起初效果很好,让我可以快速编写测试,但遇到了常见的陷阱,即测试类变得过于死板,无法在表弟之间共享我的代码子类和逻辑在继承树中被混淆。例如,我有两个都继承自 ModifyVolumeTest 的抽象 RotateVolumeTest 和 TranslateVolumeTest 类,但我很快就知道我将要旋转 翻译一个卷,所以这将是一个问题。
  2. 通过接口使用组合:这解决了以前方法的很多问题,让我可以灵活地重用代码进行测试,但它会导致大量抽象和看似“类膨胀”——现在我有 IVolumeModifier、ISetsUp 等,所有这些都使代码在测试中的实际作用变得不那么清晰。
  3. 静态实用程序类中的辅助方法:这非常有用,尤其是对于使用工厂模式快速生成测试所需的复杂对象时。但是,将一些我知道实际上并不是很通用的方法放在那里感觉很“恶心”,而是用于需要共享非常特定代码的一小部分测试。
  4. 使用 xUnit.net 或类似的测试框架通过测试套件中的 [SetUp] 和 [TearDown] 方法共享代码,通常都在同一个类中:我非常喜欢这种方法,因为它提供了我想要的可重用性,而无需从测试代码中抽象出来,但我的团队对此不感兴趣;我试图展示在我们的测试中采用这样的框架的潜在好处,但共识似乎是,在重写我们现有的测试类时进行重构工作是不值得的。这是一个有效的观点,我认为我不太可能进一步说服他们,尤其是作为一个相对较新的员工,所以除非我想让我的测试类与代码库的其他部分大不相同,否则这个是不可能的.
  5. 在需要的地方复制和粘贴代码:这是我们目前使用的方法,以及 #3 和向 TestBase 添加方法。我知道对于测试代码是否可以接受复制/粘贴编码,但我觉得从长远来看,使用这种方法将使我的测试更难维护或更改,因为如果出现错误,我现在有 N 个需要修复逻辑的地方(已经有很多地方需要修复了)。

在这一点上,我真的不确定我还有什么其他选择,只能选择 #5,因为它会减慢我快速或稳健地编写测试的能力,以便与当前代码库保持一致。非常感谢任何想法或意见。

【问题讨论】:

    标签: testing design-patterns abstraction code-reuse acceptance-testing


    【解决方案1】:

    我个人认为,对于一个成功的测试框架来说,最重要的是抽象。让编写测试尽可能简单。对我来说,关键是你最终会得到更多的测试,而作者更多地关注他们正在测试的内容,而不是如何编写测试。我见过的每一个不关注抽象的测试框架都以多种方式失败,最终成为可维护性的噩梦。

    如果逻辑只用于单个测试类,则保留在该测试类中,但如果在多个地方需要它,则稍后重构

    我会选择除了 #5 之外的所有选项。

    【讨论】:

    • 我完全同意抽象在最终使测试代码更具可读性和更易于编写方面的重要性。不幸的是,我未能成功说服我的团队,所以看起来 #3 和 #5 是赢家。
    • 让他们像我一样艰难地学习。我已经看到它以两种方式完成,并且抽象要好十倍并且维护更少,也就是 #5 单独会增加维护。
    猜你喜欢
    • 2014-09-30
    • 2012-03-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-25
    • 2011-10-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多