本文檔講解了我們是如何使用JSCover來獲得Selenium的測試樣例的js代碼文件的執行覆蓋率的。
事實上網上有挺多博客講這玩意兒了,不過完全按照網上已有的教程去弄的的話,並無法滿足我們的需要。
參考鏈接:
- https://www.cnblogs.com/bhlsheji/p/4
- https://stackoverflow.com/questions/9495625/selenium-is-there-any-js-javascript-code-coverage-tool-which-we-can-integrate
- http://tntim96.github.io/JSCover/manual/manual.xml
工具介紹
Selenium
瀏覽器自動化測試工具。可以模擬用戶對瀏覽器的操作,從而起到自動化測試的效果。具體怎么用,網上一堆教程,不贅述了。
selenium會在測試樣例的編寫中被使用,我們還會使用selenium的executeScript調用JSCover提供的hook來保存覆蓋率數據。
JSCover
js代碼覆蓋率檢測工具。原理是插樁js代碼,該項目在github上開源,它也有托管在github上的官網。附帶一提,根據我的使用經驗來看,有問題不要查百度、也不要查它的user manual,而是應該查github上的issue。
JSCover我們只使用它的JSCover-all.jar
文件,下下來以后就拿出來這個就行了。
原理性流程
- 使用JSCover對js代碼進行插樁,使得我們能夠獲得代碼覆蓋率。
- 對插樁后的代碼執行測試樣例。
- 將各測試樣例的代碼覆蓋率導出保存起來。
- 合並各測試樣例的代碼覆蓋率
- 使用合並后的代碼覆蓋率文件生成測試報告
流程示意圖
實際流程的分步講解
0. 預准備jscoverage.js
這一步是因為jscover自身存在的問題,原因之后再講解。總之先得在不啟用local-storage的情況下對代碼進行一次插樁,得到jscoverage.js
。
示例指令:java -Dfile.encoding=UTF-8 -jar JSCover-all.jar -fs D:/code_origin D:/code_instrumented
-Dfile.encoding=UTF-8
:設定編碼,避免網頁代碼中的中文在插樁后變成亂碼。-jar JSCover-all.jar
:指定JSCover-all.jar
的所在路徑。-fs
:指定使用文件插樁模式。我們只使用該模式,除此之外還有proxy模式,不過我們不使用,原因見最下。D:/code_origin
和D:/code_instrumented
:前者為原來的js代碼文件所在的目錄,后者為想把插樁后的代碼保存到的目錄。
執行完上述指令后,應該就能在插樁后的代碼的所在目錄(也就是示例中的D:/code_instrumented
)中找到jscoverage.js
文件,將它保存到一個合適的地方,留待之后使用。
1. 代碼插樁
代碼插樁分為兩部分,一部分是給網頁的js代碼文件插樁,使得執行時能夠得到覆蓋率變量。另一部分是在測試樣例的執行末尾利用selenium提供的executeScript調用JSCover提供的hook,這本質就是個動態插樁的過程,它使得我們能夠保存下來覆蓋率數據。
網頁的js代碼文件插樁
示例指令:java -Dfile.encoding=UTF-8 -jar JSCover-all.jar -fs --local-storage D:/code_origin D:/code_instrumented
事實上,它和上一步“預准備”中的指令的差別僅在於--local-storage
而已。local-storage
的含義是“是否啟用HTML5的local-storage功能來保存代碼覆蓋率變量”。如果不啟用的話,JSCover就會用一個js變量來保存代碼覆蓋率變量,而眾所周知,js變量是無法跨頁面的,這也就導致每當我們切換頁面時,代碼覆蓋率變量就會丟失。所以我們需要啟用local-storage
來保存代碼覆蓋率變量。
不過JSCover在local-storage
模式下生成的jscoverage.js
文件存在bug,所以我們在上一步“預准備”時需要先在非local-storage
下生成一個jscoverage.js
文件。這個文件僅僅是用來顯示測試報告用的,不會影響到代碼覆蓋率數據。
hook調用
這一部分可以參考參考鏈接3(官方手冊)中的做法。官網代碼的python版:
json_str = driver.execute_script("return jscoverage_serializeCoverageToJSON();")
之后將json_str保存成jscoverage.json
,然后放到插樁后的代碼所在目錄下,覆蓋掉原來的jscoverage.json
文件就行了。
不過因為官網這種做法是一個類一個jscoverage.json
,一個類在selenium中就表示一類測試樣例,而我們有好多好多類測試樣例,所以就會有好多好多代碼覆蓋率文件jscoverage.json
。所以我們需要在執行時分別保存它們,在全部執行完后再合並它們。合並會在后面再講解。
假設我們有三個Selenium的測試類,分別將叫TC_A, TC_B, TC_C。那我們可以生成類似以下的一個目錄結構
- coverage
- TC_A
- jscoverage.json
- TC_B
- jscoverage.json
- TC_C
- jscoverage.json
這僅僅只需要在保存json_str時操作一下就行了,不再贅述。
2. 執行測試樣例
這一部分和平時一模一樣,僅僅需要注意要執行插樁后的網頁代碼文件,而不是插樁前的。
3. 合並代碼覆蓋率文件
在執行測試樣例后,一切正常的話,就能得到類似在第一步中描述的那樣的代碼覆蓋率文件的目錄結構了:
- coverage
- TC_A
- jscoverage.json
- TC_B
- jscoverage.json
- TC_C
- jscoverage.json
示例指令: java -cp JSCover-all.jar jscover.report.Main --merge coverage/* D:/code_instrumented
coverage/*
:也就是上述的目錄結構的頂層目錄的路徑。D:/code_instrumented
:合並后的代碼覆蓋率文件的保存目錄。我們直接指定為插樁后的代碼的所在目錄,省去手動覆蓋的麻煩。
注意,如果只有一個jscoverage.json的話,是無法使用上述指令進行合並的,畢竟只有一個,JSCover會報錯。這時候請手動復制那唯一一個jscoverage.json
,覆蓋掉原來的jscoverage.json
。
4. 生成測試報告
把我們在“預准備”時搞到的jscoverage.js
翻出來,然后覆蓋掉插樁后的代碼所在目錄下的jscoverage.js
,再修改一下它,將jscoverage_isReport
改為true:
var jscoverage_isReport = true;
最后打開jscoverage.html
即可。可能會啥都沒,這時候你打開瀏覽器的控制台看看報啥錯吧,例如chrome的話,通常而言都是Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-extension, https.
,然后百度百度解決一下,或者換個瀏覽器再試試,或者自己改改jscoverage.html
,都行。我是最后直接用Edge打開了。
最后應該是這樣子的:
點開一個文件的話,就能看見哪些行被覆蓋了,哪些沒有:
不使用JSCover的Proxy模式的原因
Proxy模式要方便很多,可以省去插樁網頁代碼的步驟。因為proxy模式下,jscover會截獲所有瀏覽器的發包和收包,對於所有發過來的js文件,它都會自動進行插樁。
不過因為JSCover的Proxy模式需要修改瀏覽器代理。而我們目前的本地測試環境使用了Fiddler作為瀏覽器代理,這兩個代理沖突了,也就只能二選一,所以我們沒有使用JSCover的Proxy模式,不過要是你的項目不使用瀏覽器代理來搭建本地測試環境,可以考慮用用JSCover的proxy模式,真的方便很多。