测试驱动开发
了解何时添加新测试,并熟悉测试驱动开发。
概述
何时添加新测试?在项目的哪个阶段和开发周期中进行?通常的做法是,在发现缺陷之后引入新的测试。
每一个新的生产环境缺陷都反映出已有测试的不足,因此我们需要添加一个测试来验证该问题已被解决,并确保其不会再次发生。
另一种情况是在我们准备重构代码之前,可能需要立即添加新的测试。通过为代码编写测试,我们可以固化当前所有使用场景下的行为,从而保证在重构前一切功能正常。
这种方法尤其适用于处理遗留代码。在这种情况下,编写测试有助于我们理解现有代码库中各个组件的工作方式。
测试驱动开发
测试驱动开发(TDD) 是一种软件开发方法,可分为两个步骤:
- 首先编写测试,这些测试定义了未来的 API、需求和使用场景。
- 然后编写代码以通过这些测试。
在这种方法中,应在编写代码之前将软件需求转化为测试用例。这与先开发软件再补充测试的传统做法正好相反。
TDD 生命周期
测试驱动开发包含以下一系列步骤:
- 添加一个测试。
- 运行所有测试,新测试应因预期原因失败。
- 编写最简单的可通过该测试的代码。
- 此时所有测试都应通过。
- 根据需要进行重构,并在每次重构后运行测试,确保功能保持不变。
因此,TDD 要求我们在编写实际代码之前,先为某个功能或特性编写测试;然后实现代码使其通过测试;对每个新功能或修改重复这一过程。
TDD 的优势有哪些?
TDD 的主要优势之一是帮助开发者在开发早期识别并修复缺陷。通过先编写测试,开发者可以确保所写的代码符合需求并按预期工作。这样可以在问题变得严重之前及时发现,从而节省时间和成本。
另一个优势是提升代码质量。由于每个功能和函数都需要编写测试,开发者必须思考代码的使用方式以及与其他模块的交互方式。这促使代码设计更加合理,易于理解和维护。
TDD 还有助于优化整体开发流程。通过边写代码边测试,开发者可以一次专注于小块功能,更集中地完成任务。这有助于加快开发速度,提高工作效率。
最后,TDD 有助于提升软件的可靠性和健壮性。在发布前充分测试代码,开发者可以更有信心地确认软件能正常运行,且所有已知问题都已被识别和修复。这将带来更好的用户体验,并提高产品成功率。
总之,TDD 能够提升软件质量、缩短开发周期、优化工作流程。它推动开发者在开发早期发现和修复缺陷,同时增强软件的可靠性与稳定性。
练习
让我们尝试基于一组测试来编写代码。
众所周知,Lasso 回归(带 L1 正则化的线性回归)倾向于将贡献较小的特征权重置为零,而 Ridge 回归(带 L2 正则化的线性回归)则只是将其权重缩小。正因如此,Lasso 常被用作特征选择(或称特征过滤)的辅助模型。
以下是 tests.py 中定义的一个测试集,它规定了内部使用 Lasso 的特征选择器类的 API。请尝试编写满足所有测试要求的代码。
1class LassoSelector: 2 pass
TDD 的局限性
TDD 不仅在测试方面,甚至在整个开发方式上都是一种较为激进的方法。它最初由极限编程(XP)软件开发方法推广开来,也就不足为奇了。
TDD 并非适用于所有项目。并非每个项目都百分之百适合采用 TDD,具体适用性可能受限于可用时间、团队能力、产品复杂度、迭代和更新频率等因素。
熟悉 TDD 并在合适场景中加以应用,是非常有价值的。
兼顾两种方法的优势
在一个项目中同时采用两种方法并无障碍:
- 在添加新功能或模块时(如果有足够时间),使用 TDD 方法;
- 当出现新缺陷时,补充相应的测试;
- 在重构前增加更多测试,并在重构过程中持续更新测试,以确保重构未影响系统的正常运行。