【发布时间】:2020-06-02 13:46:21
【问题描述】:
我最近被聘为我工作团队的一员,该团队的重点是为我们公司的 3D 建模软件编写验收测试套件。我们使用内部 C# 框架来编写和运行它们,这基本上相当于继承 TestBase 类并覆盖 Test() 方法,通常所有设置、测试和拆卸都在此完成。
在编写测试时,我注意到我的很多代码最终都是我经常重写的样板代码。我一直有兴趣尝试提取该代码以使其可重用并使我的代码更干燥,但我一直在努力寻找一种方法来做到这一点,而不会过度抽象我的测试,而这些测试应该基本上是独立的。我尝试了多种方法,但都遇到了问题:
- 使用继承: 最简单的解决方案,起初效果很好,让我可以快速编写测试,但遇到了常见的陷阱,即测试类变得过于死板,无法在表弟之间共享我的代码子类和逻辑在继承树中被混淆。例如,我有两个都继承自 ModifyVolumeTest 的抽象 RotateVolumeTest 和 TranslateVolumeTest 类,但我很快就知道我将要旋转 和 翻译一个卷,所以这将是一个问题。
- 通过接口使用组合:这解决了以前方法的很多问题,让我可以灵活地重用代码进行测试,但它会导致大量抽象和看似“类膨胀”——现在我有 IVolumeModifier、ISetsUp 等,所有这些都使代码在测试中的实际作用变得不那么清晰。
- 静态实用程序类中的辅助方法:这非常有用,尤其是对于使用工厂模式快速生成测试所需的复杂对象时。但是,将一些我知道实际上并不是很通用的方法放在那里感觉很“恶心”,而是用于需要共享非常特定代码的一小部分测试。
- 使用 xUnit.net 或类似的测试框架通过测试套件中的 [SetUp] 和 [TearDown] 方法共享代码,通常都在同一个类中:我非常喜欢这种方法,因为它提供了我想要的可重用性,而无需从测试代码中抽象出来,但我的团队对此不感兴趣;我试图展示在我们的测试中采用这样的框架的潜在好处,但共识似乎是,在重写我们现有的测试类时进行重构工作是不值得的。这是一个有效的观点,我认为我不太可能进一步说服他们,尤其是作为一个相对较新的员工,所以除非我想让我的测试类与代码库的其他部分大不相同,否则这个是不可能的.
- 在需要的地方复制和粘贴代码:这是我们目前使用的方法,以及 #3 和向 TestBase 添加方法。我知道对于测试代码是否可以接受复制/粘贴编码,但我觉得从长远来看,使用这种方法将使我的测试更难维护或更改,因为如果出现错误,我现在有 N 个需要修复逻辑的地方(已经有很多地方需要修复了)。
在这一点上,我真的不确定我还有什么其他选择,只能选择 #5,因为它会减慢我快速或稳健地编写测试的能力,以便与当前代码库保持一致。非常感谢任何想法或意见。
【问题讨论】:
标签: testing design-patterns abstraction code-reuse acceptance-testing