不熟悉cdp的可以參見前文:Chrome remote debugging protocol在自動化測試中的應用和實踐
cov的數據結構
首先,使用takePreciseCoverage方法來拿到js執行數據,這個數據的數據結構是這樣的:
'result': {
'result': [{
'scriptId': '17',
'url':'https://www.xxxxxxxxx.com/browser/guide.js',
'functions': [{
'functionName': 'get',
'ranges': [{
'startOffset': 0,
'endOffset': 4273,
'count': 1
}],
'isBlockCoverage': False
},
}],
}],
}
......
一個result包含多個js的統計情況,每個url基本就是js的請求地址;在每個js的統計情況里,又有多個function的統計情況,每個function里的startOffset和endOffset指的是這個方法的被統計語句按字節位置來算的開始位置和結束位置,count代表這段語句是否被執行到,1代表是,0代表否。
因此,思路就是,拿到測試完成后的js統計數據,然后通過每個js統計數據里的每個function的統計坐標值和統計狀態,和原始js數據比對,從而實現對js覆蓋狀況的總覽。
下面說一下具體流程。
過濾cov數據
cov數據(也就是上文的js統計數據)不是直接可用的,因為首先獲取到的覆蓋率是十分全面的,全面到會有很多額外的你不想要的數據,比如通用的js類庫,還有dev tools操作時的js數據等等,所以第一步是過濾cov數據。
過濾分為兩步,第一步是過濾掉你不需要的js統計數據,這里根據主域名來過濾,具體是寫了cov_domain_filter()這個方法(詳見源碼,下同。),接受一個數組,數組內容是你要過濾的主域名列表,然后返回給你只留下含有主域名的js的統計數據。
第二步,因為這個統計數據包含了所有的執行狀態的統計,包括覆蓋到的和未覆蓋到的,我們只需要標注出未覆蓋到的代碼,就可以體現出覆蓋情況,因此這里進一步過濾了狀態,只留下了未覆蓋到的代碼的統計情況,具體方法是cov_not_count_filter()。
至此,我們的數據就過濾完成了。
合并cov數據
仔細研究了一下cov數據,發現每個js的統計數據里,會有相同的function的統計數據,例如前面有一個function test,他的數據是{startoffset:10;endoffset:29},后面又可能存在一個unction test,他的數據是{startoffset:30;endoffset:60},當然他們的數據不一樣,我猜測他是根據測試的進程,不斷的在js的統計數據里追加方法統計數據,這點沒有徹底的領悟作者的意圖。
出于后面的統計結果展示方便,這里我把這種數據都給合并了,例如前文的例子,把他的數據合并了就是{startoffset:10;endoffset:60},這樣每個js的統計數據里,只可能存在一個方法,每個方法會有多個不可再合并的統計數據,這里的方法是merge_same_func_ranges。
對比和追加cov數據
如果只進行一次的測試過程的覆蓋率收集,那么這一步是不必要做的,但是,考慮到一個模塊可能要多個測試用例才能覆蓋完流程分支,那么要想獲得這個模塊的覆蓋率,就只有在每個用例完成后,將收集的cov數據和前一次的進行對比和追加。
這里是寫的很痛苦了,因為cov的數據結構不是我是谷歌制定的,本身對于為什么要這么設計也并不理解充分,這個數據結構層級非常的深,所以要對比并進行追加就非常的繁瑣,這里用了大量的列表推導式來代替for循環,否則for循環會更多,這個方法是make_covdata_file。
將cov數據最終展示
cov數據處理完,還需要一個網頁進行展示,這里是用了一個模板類,通過設立html模板,將數據替換,再生成從而實現了簡單的網頁展示,如果你有更高的需求可以自行進行設計。
這里要說的是著色器模塊,也就是給數據上背景色,設計上是通過對未覆蓋的代碼兩端插入背景色的html代碼來實現未覆蓋代碼的醒目展示,這里存在一個算法問題,因為你不能直接根據代碼的起始坐標(也就是startoffset和endoffset)直接插入背景色html代碼,因為當你第一次插入的時候是沒問題的,但你要在下一個坐標插入的時候,就會出問題,因為你之前插入了代碼的緣故,對下一個坐標而言,已經不是真實坐標了,需要加上之前背景色代碼的偏移量。
這里我不(jiu)得(shi)已(lan)采用了一個非常犧牲性能的辦法,就是直接拿cov數據復制出副本,用需要加背景的代碼的起始坐標拿出這部分的字符串,然后在副本里搜索并添加背景代碼,然后再替換回去(捂臉哭)。
最終的展示效果
這里我做了一個簡單的本地文件作為示例,看一下最終結果。
為了方便演示,整個profiler模塊被我集成進了之前的一個ui測試框架里,例子也直接扔進去了,只需要把這個項目clone下來,然后把環境變量修改為你的,再運行process模塊就可以體驗,當然你也可以直接使用這個模塊。
項目地址:https://github.com/icesword0760/uitest-keyword
一些tips
1.不能用于壓縮混淆后的js上;
2.因為展示部分的著色器算法性能損耗過大,所以如果你要生成報告的話會很慢,有興趣的可以自己重寫這部分。
3.php項目,結合博客里的php覆蓋率統計方法,可以和這個模塊一起做到前后端代碼覆蓋率統計。