JavaScript覆蓋率統計實現,javascript覆蓋率

來源:互聯網
上載者:User

JavaScript覆蓋率統計實現,javascript覆蓋率
主要需求1、 支援browser & nodejs

因為javascript既可以在瀏覽器環境運行,也可以在nodejs環境運行,因此需要能夠統計兩種環境下單元測試的覆蓋率情況。

2、 透明、無縫

使用者寫單元測試用例的時候,不需要為了支援覆蓋率統計多寫代碼,之前寫的用例無需修改就可以直接統計覆蓋率情況。

原理

javascript覆蓋率的相關文章比較少,下面的圖是通過閱讀開源javascript覆蓋率工具istanbul及開源測試架構Karma的覆蓋率外掛程式karma-coverage得出的。javascript覆蓋率統計的核心思想是,在原始碼相應的位置注入統計代碼,當代碼運行之後,根據統計代碼統計的資料確定程式啟動並執行路徑,最終產生覆蓋率統計報告。

1. 轉換(instrument)
  • 使用開源工具Esprima對原始碼進行文法分析產生文法樹
  • 在文法樹相應的位置注入統計代碼,在程式執行到這個位置的時候對相應的全域變數賦值,確保執行之後能夠根據全域變數知道代碼的執行流程
  • 使用開源工具Escodegen根據注入之後的文法樹產生對應的javascript代碼,即轉換之後的代碼(instrumented code)

註:這裡進行文法分析的好處是,針對書寫不規範的代碼(比如一行多個語句),依然能夠很好統計出分支覆蓋和組合覆蓋等資訊。

2. 執行(run)

這一步需要先載入轉換後的代碼:

  • nodejs:直接通過對require語句進行hook來無縫實現,後面會詳細介紹
  • 瀏覽器環境:需要將轉換後的代碼傳給瀏覽器。如果是karma之類的帶server的測試架構,需要通過socket傳輸至瀏覽量器,執行完之後再將包含覆蓋率資訊的執行結果傳回server,產生測試報告

然後執行單元測試,產生的統計資訊會掛在全域變數this下面。對於瀏覽器環境,this就是window,而對於nodejs環境this就是global

3. 產生報告(report)

這一步會根據全域標量中的覆蓋率資訊產生特定格式的報告,如html、lcov、cobertura、teamcity等。

一個例子
//source codefunction abs(num){    if(abs > 0)        return num;    else        return -num;}
//instrumented codevar __cov_iypKC$dWI6uJFmvxThycaA = (Function('return this'))();if (!__cov_iypKC$dWI6uJFmvxThycaA.__coverage__) { __cov_iypKC$dWI6uJFmvxThycaA.__coverage__ = {}; }__cov_iypKC$dWI6uJFmvxThycaA = __cov_iypKC$dWI6uJFmvxThycaA.__coverage__;if (!(__cov_iypKC$dWI6uJFmvxThycaA['/Users/lonfee88/Codes/testframe/coverage-jasmine-istanbul-karma/abs.js'])) {   __cov_iypKC$dWI6uJFmvxThycaA['/Users/lonfee88/Codes/testframe/coverage-jasmine-istanbul-karma/abs.js'] = {"path":"/Users/lonfee88/Codes/testframe/coverage-jasmine-istanbul-karma/abs.js","s":{"1":1,"2":0,"3":0,"4":0},"b":{"1":[0,0]},"f":{"1":0},"fnMap":{"1":{"name":"abs","line":1,"loc":{"start":{"line":1,"column":-15},"end":{"line":1,"column":17}}}},"statementMap":{"1":{"start":{"line":1,"column":-15},"end":{"line":6,"column":1}},"2":{"start":{"line":2,"column":1},"end":{"line":5,"column":14}},"3":{"start":{"line":3,"column":2},"end":{"line":3,"column":13}},"4":{"start":{"line":5,"column":2},"end":{"line":5,"column":14}}},"branchMap":{"1":{"line":2,"type":"if","locations":[{"start":{"line":2,"column":1},"end":{"line":2,"column":1}},{"start":{"line":2,"column":1},"end":{"line":2,"column":1}}]}}};}__cov_iypKC$dWI6uJFmvxThycaA = __cov_iypKC$dWI6uJFmvxThycaA['/Users/lonfee88/Codes/testframe/coverage-jasmine-istanbul-karma/abs.js'];function abs(num){__cov_iypKC$dWI6uJFmvxThycaA.f['1']++;__cov_iypKC$dWI6uJFmvxThycaA.s['2']++;if(abs>0){__cov_iypKC$dWI6uJFmvxThycaA.b['1'][0]++;__cov_iypKC$dWI6uJFmvxThycaA.s['3']++;return num;}else{__cov_iypKC$dWI6uJFmvxThycaA.b['1'][1]++;__cov_iypKC$dWI6uJFmvxThycaA.s['4']++;return-num;}}
node.js整合覆蓋率

通過hook可以直接無縫的載入轉換後的代碼,可以對下面兩種語句進行hook:

  • require
  • vm.createScript

對require進行hook的代碼是通過對Module._extensions['.js']進行賦值實現的:

function hookRequire(matcher, transformer, options) {    options = options || {};    var fn = transformFn(matcher, transformer, options.verbose),        postLoadHook = options.postLoadHook &&            typeof options.postLoadHook === 'function' ? options.postLoadHook : null;    Module._extensions['.js'] = function (module, filename) {        var ret = fn(fs.readFileSync(filename, 'utf8'), filename);        if (ret.changed) {//載入instrument之後的代碼並運行            module._compile(ret.code, filename);        } else {//載入原來的代碼並運行            originalLoader(module, filename);        }        if (postLoadHook) {            postLoadHook(filename);        }    };}

hook使覆蓋率的整合變得簡單,甚至不需要寫代碼,比如Mocha的覆蓋率整合,只需要改用如下的調用方式即可:

istanbul cover _mocha -- -R spec test/spec
瀏覽器整合覆蓋率

瀏覽器整合覆蓋率就稍微麻煩一點,好在istanbul提供了API:

  1. 轉碼(調用istanbul的Instrumenter介面)
  2. 將instrumented code發送到瀏覽器(自己實現)
  3. 將包含覆蓋率資訊的執行結果發回server(自己實現)
  4. 根據返回的覆蓋率資訊產生覆蓋率報告(調用istanbul的Reporter介面)

編程實現程式碼涵蓋範圍及路徑分析檢測,C++, C#, Java, JavaScript(任選一種程式語言)

如果你採用源碼插裝的方式來做的話,需要對輸入程式進行詞法,文法分析建立文法分析樹(有一些現成的工具如bison, antlr可以藉助),通過語分析法分析樹擷取程式控制流程關係,然後就可以對程式的基本塊進行分析了。要考慮擷取覆蓋率和程式執行路徑,需要對基本塊做插裝,利用插入的探針來對它們的執行情況做記錄。
 
javascript統計新聞瀏覽次數的函數

針對一條新聞的瀏覽次數,不如在資料庫對應此條新聞增加一個欄位,用於統計瀏覽次數,初始化為0

每點擊一次這條新聞的連結,就用xmlHttp(我只會這樣。。)非同步訪問後台頁面,在背景程式中更新一下這個欄位,使之+=1,這不就行了麼。
 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.