目錄
1. 关于代码覆盖率
2. 业务背景
于是,我们现在碰到的场景是:
3. 函数覆盖率解决方案
(1)原理
(2)插桩
(3)信息存储
4. 报告生成
5. 总结
首頁 後端開發 php教程 Web端PHP代码函数覆盖率测试解决方案

Web端PHP代码函数覆盖率测试解决方案

Jun 20, 2016 pm 12:40 PM

1. 关于代码覆盖率

衡量代码覆盖率有很多种层次,比如行覆盖率,函数/方法覆盖率,类覆盖率,分支覆盖率等等。代码覆盖率也是衡量测试质量的一个重要标准,对于黑盒测 试来说,如果你不确定自己的测试用例是否真正跑过了系统里面的每一行代码,在测试的完整性上总要打些折扣。因此,业界几乎对各种编程语言都有自己的一套代 码覆盖率解决方案。世界上最美的语言PHP当然也不例外。PHPUnit和Spike PHPCoverage提供了一套基于xdebug的代码覆盖率测试方案。在本文中,我将针对自己碰到的特定业务场景,讲述一下自己进行PHP代码函数覆 盖率测试的解决方案。

2. 业务背景

假设我们在线开发了一个网站,交给业务测试的同事去进行功能测试。那他们是怎么测试的呢?通常情况下,无非是开发人员把网站部署好了,然后测试人员 把网上所有功能都试用一遍,包括一些异常使用情况。对于业务测试来说,只要我把所有的功能点都测了,把所有异常使用情况也测到了,那就完成了。但是对于开 发来说,我比较好奇的是,你是否把我写的所有代码都跑到了?会不会存在一些代码,只有在很特殊的情况下才能触发,而你从来没有测到过这些情况?这时,可能 就需要代码覆盖率来出马了。

其实我首先想到了xdebug来测试覆盖率,只需要两三个函数即可,如下:

xdebug_start_code_coverage(); //开始收集代码行覆盖情况xdebug_get_code_coverage(); //获取截至目前所跑过的代码文件名和行号xdebug_stop_code_coverage(); //停止收集代码行覆盖情况
登入後複製

xdebug提供的接口可以用于测试行覆盖率,这是否能满足要求呢?其实,行覆盖率颗粒度有点细,实际项目中,开发人员可能会对代码进行微调。比 如,这次测试,你跑过了A.php文件的第10行,但是我有一天对A.php进行了微调,在A.php第9行和第10行之间又加了两行代码。于是,原来的 第10行变为了第12行,而xdebug的行覆盖信息只记录了行号……这样之前的数据岂不是不准确了么。。。考虑再三,我觉得函数覆盖是个不错的颗粒度。 在相对成熟的项目中,很少有大规模函数变动的情况。不过问题是,xdebug并没有提供函数覆盖的接口。

于是,我们现在碰到的场景是:

【1】希望测到某次测试中所覆盖的所有函数列表,知道这个项目总共有多少个函数,计算一下覆盖率是否足够高。

【2】测试完成之后,要生成一份覆盖率报告,将代码的覆盖情况可视化。

【3】完整测试的流程如下:

其中插桩的意思是在测试执行之前的一些准备工作。

3. 函数覆盖率解决方案

(1)原理

xdebug天生提供了对行覆盖率的支持,我们要自己计算出函数覆盖率。函数覆盖率需要两点数据,一个是哪些函数被执行,一个是文件中总共有多少个函数。

文件中总共的函数量,由于我们不可能把所有函数都执行一遍,因此这部分只能通过代码静态扫描来实现。如果是在C++或者Java中,可能就需要词法 分析工具了,然而在最美的语言PHP面前,我们完全不需要那么复杂。从PHP4.3开始,PHP Zend Engine中内置了tokenizer功能,帮助开发者做源码词法分析。我们只需要找到PHP中定义函数时所对应的词法规律,就可以轻松得到指定PHP 文件中的全部函数了。

tokenizer定义的接口也十分简单:

array token_get_all (string $source)
登入後複製

该函数进行文件解析,将php源代码拆成由token组成的数组。

string token_name (int $token)
登入後複製

将整数形式的token转变为字符串形式。类似于C语言中的strerror函数。 有了tokenizer,自己再根据php函数定义的规律和格式设计一个有限状态机,即可完成全量函数的解析。这部分代码,本人写了个比较简陋的,把它单独拿出来,仅供大家参考: PHPFunctionParser

求函数覆盖率的另外一个难点在于获取被执行的函数列表。这地方让我们走了一些弯路。一开始一个最简单的办法,我们既然通过xdebug拿到被执的 行,可以通过行号来反推此行属于哪一个函数。然而每一次的请求获取的行号信息量是非常大的,如果一个求情执行了1000行,那就要进行1000次判断,效 率上会比较差。调研了一番之后,发现xdebug提供了function trace的功能,可以把一次请求中的函数调用关系获取到,只不过拿到了函数名字,却没办法得到它所在的文件。于是,再次调研一番,发现了 Reflection,给定方法名和类名,可以反推出来它在哪个文件中定义。于是我们使用function trace把函数调用关系暂存在一个临时文件中,然后通过文件解析,拿到执行的函数名(如果是类方法,则是“类名::函数名”的形式),再通过 reflection机制反推出定义这个函数的文件即可。再次体会到了世界上最美语言的强大之处。

(2)插桩

为了降低使用门槛,我们尽可能少地改变PHP源代码为好。xdebug收集信息的原理是分别调用 xdebug_start_code_coverage和xdebug_stop_code_coverage来控制覆盖率信息收集的开始和结束,因此不 可避免地要改变源代码。此处我们的解决办法是,将xdebug_stop_code_coverage通过 register_shutdown_function注册为php程序结束前必须要跑的一段程序(类似C语言的atexit函数),将其封装到一个文件 中,然后在源代码第一行require这个文件即可。如果你的PHP框架是CodeIgniter这种所有请求都有一个统一入口index.php的框 架,那就只需要改变这一个文件即可,对源代码只有一行的改动!实际上,目前基本上所有的PHP框架,都是以一个index.php文件作为所有请求的入 口。

我们对源代码的改动只有入口文件index.php的第一行加入了一句话:

<?php require_once "/file/path/to/phpcoverage.php"; ?>
登入後複製

而phpcoverage.php核心代码逻辑大致如下:

<php  …… function xdebugPhpcoverageBeforeShutdown(){  ……  $lineCovData = xdebug_get_code_coverage();  xdebug_stop_code_coverage();  ……  xdebug_stop_trace();  …… } register_shutdown_function(‘xdebugPhpcoverageBeforeShutdown’); …… xdebug_start_trace(……); xdebug_start_code_coverage(); //备注:上面省略号表示非关键代码,这里就不展示了 
登入後複製

(3)信息存储

我们的函数覆盖率测试有了思路,使用xdebug的function trace获取一次请求中所有函数的调用关系,得到执行过的所有函数,输出到文件中,通过文件解析和reflection获得被执行的函数名和该函数所在文件。将这些信息存入数据库或文件即可。

之前试用Spike的时候,我们发现这些信息以xml格式存入文件,数据冗余度很高,导致几个测试下来,文件已经非常大了。这显然不是我们想看到的。因此在数据存储的时候,我们直接将数据做json格式的序列化,字符串形式存在文件中,大大减少了文件大小。与此同时,我们再通过请求来源的IP和日期作为分隔,分别存储不同的文件。这样,来自每个机器每天的请求数据都能一目了然,向着“精准”的方向又迈进了一步,可以对测试人员的每个请求做精确的监控。下图是我们在业务实践中搜集的部分数据文件截图:

这样,来自任何一个IP的每一次Web请求,它所覆盖的行和函数信息,都会被记录到文件中。对于一般的项目测试中,也就只有几个测试人员在使用,所以不需要考虑一些性能问题。

4. 报告生成

上面讲了生成覆盖率数据的原理,不过我们至此获得的只是一份份的数据文件,如何汇总成一份完整的报告呢?这就需要我们自己来写一段脚本解析刚才生成的数据文件了。我们的做法是借鉴了开源工具spike phpcoverage的模版,并加入自己的代码逻辑,特别是加入了该工具所不具有的函数覆盖率统计数据。我们自己测试的web页面生成的报告如下:

图中可以看到每个文件的行覆盖率,函数覆盖率,还有总的覆盖率统计数据。如果需要更精确的数据,可以点进文件连接,查看到底覆盖的是哪些代码行(蓝色为覆盖,红色为未覆盖):

5. 总结

业务测试中做Web测试时,对代码的覆盖率是衡量测试质量的重要指标。我们希望通过此方法做到尽量地“精准”,测试执行完后可以精确看到哪一行代码被执行过,哪一行没被执行过。分析没被执行过的原因,从而改进测试用例。使用工具的流程也很简单,插桩=>测试=>搜集数据=>出报告。并且此解决方案最大化地减少了对业务代码的影响,只需要改一行代码即可。即便中间出现了问题,也可以快速将代码恢复为原来的样子。让测试放心,让开发也放心。

不过,最后还需要强调的一点是,并不是说覆盖了所有的代码,就证明测试已经完整了。只不过没被覆盖的话,一定是不完整的。所以这个方案最大的意义在于能够发现测试中一些遗漏的代码,找到一部分问题。其实,它也可以帮助新来的员工理解整个项目代码结构,我们可以清晰的知道,自己的每一次浏览器请求,到底在运行服务器上的哪些代码。

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

<🎜>:泡泡膠模擬器無窮大 - 如何獲取和使用皇家鑰匙
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
北端:融合系統,解釋
3 週前 By 尊渡假赌尊渡假赌尊渡假赌

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

熱門話題

Java教學
1664
14
CakePHP 教程
1423
52
Laravel 教程
1318
25
PHP教程
1269
29
C# 教程
1248
24
PHP和Python:比較兩種流行的編程語言 PHP和Python:比較兩種流行的編程語言 Apr 14, 2025 am 12:13 AM

PHP和Python各有優勢,選擇依據項目需求。 1.PHP適合web開發,尤其快速開發和維護網站。 2.Python適用於數據科學、機器學習和人工智能,語法簡潔,適合初學者。

說明PHP中的安全密碼散列(例如,password_hash,password_verify)。為什麼不使用MD5或SHA1? 說明PHP中的安全密碼散列(例如,password_hash,password_verify)。為什麼不使用MD5或SHA1? Apr 17, 2025 am 12:06 AM

在PHP中,應使用password_hash和password_verify函數實現安全的密碼哈希處理,不應使用MD5或SHA1。1)password_hash生成包含鹽值的哈希,增強安全性。 2)password_verify驗證密碼,通過比較哈希值確保安全。 3)MD5和SHA1易受攻擊且缺乏鹽值,不適合現代密碼安全。

PHP行動:現實世界中的示例和應用程序 PHP行動:現實世界中的示例和應用程序 Apr 14, 2025 am 12:19 AM

PHP在電子商務、內容管理系統和API開發中廣泛應用。 1)電子商務:用於購物車功能和支付處理。 2)內容管理系統:用於動態內容生成和用戶管理。 3)API開發:用於RESTfulAPI開發和API安全性。通過性能優化和最佳實踐,PHP應用的效率和可維護性得以提升。

PHP:網絡開發的關鍵語言 PHP:網絡開發的關鍵語言 Apr 13, 2025 am 12:08 AM

PHP是一種廣泛應用於服務器端的腳本語言,特別適合web開發。 1.PHP可以嵌入HTML,處理HTTP請求和響應,支持多種數據庫。 2.PHP用於生成動態網頁內容,處理表單數據,訪問數據庫等,具有強大的社區支持和開源資源。 3.PHP是解釋型語言,執行過程包括詞法分析、語法分析、編譯和執行。 4.PHP可以與MySQL結合用於用戶註冊系統等高級應用。 5.調試PHP時,可使用error_reporting()和var_dump()等函數。 6.優化PHP代碼可通過緩存機制、優化數據庫查詢和使用內置函數。 7

PHP的持久相關性:它還活著嗎? PHP的持久相關性:它還活著嗎? Apr 14, 2025 am 12:12 AM

PHP仍然具有活力,其在現代編程領域中依然佔據重要地位。 1)PHP的簡單易學和強大社區支持使其在Web開發中廣泛應用;2)其靈活性和穩定性使其在處理Web表單、數據庫操作和文件處理等方面表現出色;3)PHP不斷進化和優化,適用於初學者和經驗豐富的開發者。

PHP類型提示如何起作用,包括標量類型,返回類型,聯合類型和無效類型? PHP類型提示如何起作用,包括標量類型,返回類型,聯合類型和無效類型? Apr 17, 2025 am 12:25 AM

PHP類型提示提升代碼質量和可讀性。 1)標量類型提示:自PHP7.0起,允許在函數參數中指定基本數據類型,如int、float等。 2)返回類型提示:確保函數返回值類型的一致性。 3)聯合類型提示:自PHP8.0起,允許在函數參數或返回值中指定多個類型。 4)可空類型提示:允許包含null值,處理可能返回空值的函數。

PHP與Python:了解差異 PHP與Python:了解差異 Apr 11, 2025 am 12:15 AM

PHP和Python各有優勢,選擇應基於項目需求。 1.PHP適合web開發,語法簡單,執行效率高。 2.Python適用於數據科學和機器學習,語法簡潔,庫豐富。

PHP和Python:代碼示例和比較 PHP和Python:代碼示例和比較 Apr 15, 2025 am 12:07 AM

PHP和Python各有優劣,選擇取決於項目需求和個人偏好。 1.PHP適合快速開發和維護大型Web應用。 2.Python在數據科學和機器學習領域佔據主導地位。

See all articles