按调用者测量覆盖率

按调用者测量覆盖率

💡 原文英文,约700词,阅读约需3分钟。
📝

内容提要

文章提出“按调用者测量覆盖率”的新想法。作者在BASIC解释器中重构代码,将参数检查移入辅助函数,但失去对每个函数名错误参数测试的覆盖信息。通过装饰器为每个调用点创建独立上下文,实现分别测量,但需改进上下文嵌套和配置驱动。

🔎

延伸解读

重构与覆盖率测量的权衡

文章展示了重构中常见的权衡:将重复代码提取到辅助函数(如expects)提高了可维护性,但可能丢失细粒度的测试覆盖信息。原始代码中每个错误分支独立成行,能直观看出哪些函数名未测试错误参数;重构后,这些分支合并到辅助函数中,覆盖率报告只能显示辅助函数整体是否被执行,无法区分不同调用点。这种信息丢失可能影响测试的充分性评估,尤其当函数有多个调用者且行为依赖调用参数时。

按调用者覆盖率的实现思路

作者提出通过装饰器为每个调用点创建独立覆盖率上下文,利用coverage.py的动态上下文功能。装饰器在函数调用时切换上下文,记录调用者位置(文件名和行号),函数返回后恢复原上下文。这需要coverage.py的switch_context返回先前上下文以支持嵌套。概念验证成功,但仍有改进空间,如后处理显示缺失行、支持子上下文、以及通过配置驱动而非源码装饰器。

潜在应用与局限

该技术不仅限于参数检查,还可用于根据函数参数值(如func_name)作为上下文,实现更细粒度的覆盖分析。但当前实现存在局限:上下文会覆盖已有测试名称,且需要修改源码。未来若通过配置驱动,可减少对代码的侵入性。此外,后处理缺失行信息是实际使用中的关键需求,目前尚未实现。

Q&A

什么是按调用者测量覆盖率?

按调用者测量覆盖率是一种新的覆盖率测量方法,它允许分别测量函数中每个调用点的代码覆盖情况,而不是只测量整个函数的总体覆盖率。

作者为什么想要按调用者测量覆盖率?

作者在重构BASIC解释器代码时,将参数检查移入辅助函数,导致无法区分每个函数名是否都测试了错误参数。按调用者测量覆盖率可以恢复这种细粒度的覆盖信息。

按调用者测量覆盖率是如何实现的?

通过一个装饰器,在函数调用时切换coverage.py的上下文,以调用点的文件名和行号命名新上下文,并在函数返回时恢复原上下文。同时需要修改coverage.py使switch_context返回前一个上下文以支持嵌套。

按调用者测量覆盖率目前有哪些局限性?

局限性包括:需要后处理来显示缺失行;上下文会覆盖已有的测试名称上下文,需要子上下文来同时跟踪多个上下文;需要源码装饰器,理想情况应由配置驱动。

按调用者测量覆盖率与传统的覆盖率测量有何不同?

传统覆盖率测量只显示函数整体的覆盖情况,而按调用者测量覆盖率可以区分每个调用点的覆盖情况,从而发现哪些调用路径未被测试。

作者在BASIC解释器中重构代码时遇到了什么问题?

重构前,每个内置函数都有独立的参数检查代码,覆盖率可以显示每个函数是否测试了错误参数。重构后,参数检查集中在辅助函数中,覆盖率只能显示辅助函数整体被测试,无法区分每个函数名是否都测试了错误参数。

🏷️

标签

➡️

继续阅读