摘要:的另一種形式測(cè)試踩坑之路代碼覆蓋率單元測(cè)試的代碼覆蓋率統(tǒng)計(jì),是衡量測(cè)試用例好壞的一個(gè)的方法。
項(xiàng)目地址: diana造輪子的意義文檔地址: http://muyunyun.cn/diana/
為啥已經(jīng)有如此多的前端工具類庫(kù)還要自己造輪子呢?個(gè)人認(rèn)為有以下幾個(gè)觀點(diǎn)吧:
定制性強(qiáng),能根據(jù)自己的需求為主導(dǎo)延伸開(kāi)發(fā)。萬(wàn)一一不小心還能幫到別人(比如 React 庫(kù));
紙上得來(lái)終覺(jué)淺,很多流行的庫(kù),只是照著它們的 API 進(jìn)行使用,其實(shí)這些庫(kù)里蘊(yùn)含著大量的知識(shí)、技巧,最好的辦法就是仿照它們來(lái)寫些小 demo,從而體會(huì)這些庫(kù)的精髓;
造輪子的過(guò)程中能讓自己體會(huì)到與平常業(yè)務(wù)開(kāi)發(fā)不一樣的樂(lè)趣;比如和日常業(yè)務(wù)開(kāi)發(fā)中很大的一個(gè)區(qū)別是會(huì)對(duì)測(cè)試用例具有比較嚴(yán)格的要求;而且寫文檔能力提升了。
就先瞎編到這里了。。。
拋開(kāi)內(nèi)部方法(寫相應(yīng)的專題效果可能會(huì)更好,所以這里先略過(guò)),下面分享一些開(kāi)發(fā) diana 庫(kù) 時(shí)的一些心得:
項(xiàng)目目錄結(jié)構(gòu)├── LICENSE 開(kāi)源協(xié)議 ├── README-zh_en.md 英文說(shuō)明文檔 ├── README.md 中文說(shuō)明文檔 ├── coverage 代碼覆蓋率文件 ├── docs 文檔目錄 │?? └── static-parts │?? ├── index-end.html 靜態(tài)文檔目錄結(jié)尾文件 │?? └── index-start.html 靜態(tài)文檔目錄開(kāi)頭文件 ├── karma.conf.js karma 配置文件 ├── lib │?? ├── diana.back.js 服務(wù)端引用入口 │?? └── diana.js 瀏覽器引用入口 ├── package.json ├── script │?? ├── build.js 構(gòu)建文件 │?? ├── check.js 結(jié)合 pre-commit 進(jìn)行 eslint 校驗(yàn) │?? ├── tag-script.js 自動(dòng)生成文檔的標(biāo)簽 │?? ├── web-script.js 自動(dòng)生成文檔 │?? ├── webpack.browser.js 瀏覽器端 webpack 配置文件 │?? └── webpack.node.js 服務(wù)器端 webpack 配置文件 ├── snippets ├── src │?? ├── browser 瀏覽器端方法 │?? ├── common 共用方法 │?? ├── node node 端方法 │?? └── util.js 庫(kù)內(nèi)通用方法 ├── tag_database 文檔標(biāo)簽 └── test 測(cè)試文件 ├── browserTest ├── commonTest ├── index.js └── nodeTest
目錄結(jié)構(gòu)也隨著方法的增多在不停迭代當(dāng)中,建議直接到庫(kù)中查看最新的目錄結(jié)構(gòu)。
相應(yīng)地,具體的方法會(huì)隨著時(shí)間迭代,所以首先推薦查看文檔,點(diǎn)擊如下圖的 ? 就能查看源碼。
讓模塊同時(shí)在 Node.js 與瀏覽器中運(yùn)行我們可以通過(guò)如下方法來(lái)判斷模塊當(dāng)前是運(yùn)行在 Node.js 還是瀏覽器中,然后使用不同的方式實(shí)現(xiàn)我們的功能。
// Only Node.JS has a process variable that is of [[Class]] process const isNode = Object.prototype.toString.call(typeof process !== "undefined" ? process : 0) === "[object process]"
但如果用戶使用了模塊打包工具,這樣做會(huì)導(dǎo)致 Node.js 與瀏覽器的實(shí)現(xiàn)方式都會(huì)被包含在最終的輸出文件中。針對(duì)這個(gè)問(wèn)題,開(kāi)源社區(qū)提出了在 package.json 中添加 browser 字段的提議,目前 webpack 和 rollup 都已經(jīng)支持這個(gè)字段了。
給 browser 字段提供一個(gè)文件路徑作為在瀏覽器端使用時(shí)的模塊入口,但需要注意的是,打包工具會(huì)優(yōu)先使用 browser 字段指定的文件路徑作為模塊入口,所以你的 main 字段 和 module 字段會(huì)被忽略,但是這會(huì)導(dǎo)致打包工具不會(huì)優(yōu)化你的代碼。詳細(xì)信息請(qǐng)參考這個(gè)問(wèn)題。
在 diana 庫(kù) 為了在不同環(huán)境中使用適當(dāng)?shù)奈募?,?package.json 中進(jìn)行了如下聲明:
"browser": "lib/diana.js", "main": "lib/diana.back.js", // 或者 "module": "lib/diana.back.js",
這樣一來(lái),在 node 環(huán)境中,引用的是 lib/diana.back.js 文件,在瀏覽器環(huán)境中,引用的是 lib/diana.js 文件。然后就能愉快地在瀏覽器端和 node 端愉快地使用自己特有的 api 了。
常見(jiàn)模塊規(guī)范比較另外為了使 diana 庫(kù) 的打包文件兼容 node 端、以及瀏覽器端的引用,選擇了 UMD 規(guī)范進(jìn)行打包,那么為什么要選擇 UMD 規(guī)范呢?讓我們看下以下幾種規(guī)范之間的異同:
CommonJSCommonJs 是服務(wù)器端模塊的規(guī)范,Node.js 采用了這個(gè)規(guī)范。這些規(guī)范涵蓋了模塊、二進(jìn)制、Buffer、字符集編碼、I/O流、進(jìn)程環(huán)境、文件系統(tǒng)、套接字、單元測(cè)試、服務(wù)器網(wǎng)關(guān)接口、包管理等。
根據(jù) CommonJS 規(guī)范,一個(gè)多帶帶的文件就是一個(gè)模塊。加載模塊使用 require 方法,該方法讀取一個(gè)文件并執(zhí)行,最后返回文件內(nèi)部的 exports 對(duì)象。
CommonJS 加載模塊是同步的。像 Node.js 主要用于服務(wù)器的編程,加載的模塊文件一般都已經(jīng)存在本地硬盤,所以加載起來(lái)比較快,不用考慮異步加載的方式,所以 CommonJS 規(guī)范比較適用。但如果是瀏覽器環(huán)境,要從服務(wù)器加載模塊,這是就必須采用異步模式。所以就有了 AMD、CMD 解決方案。
AMD、CMDAMD 是 RequireJS 在推廣過(guò)程中對(duì)模塊定義的規(guī)范化產(chǎn)物。AMD 推崇提前執(zhí)行。
// AMD 默認(rèn)推薦的是 define(["./a", "./b"], function(a, b) { a.doSomething() b.doSomething() ... })
CMD 是 SeaJS 在推廣過(guò)程中對(duì)模塊定義的規(guī)范化產(chǎn)物。CMD 推崇依賴就近。
// CMD define(function(require, exports, module) { var a = require("./a") a.doSomething() var b = require("./b") b.doSomething() ... })UMD
UMD 是 AMD 和 CommonJS 的結(jié)合。因?yàn)?AMD 是以瀏覽器為出發(fā)點(diǎn)的異步加載模塊,CommonJS 是以服務(wù)器為出發(fā)點(diǎn)的同步加載模塊,所以人們想出了另一個(gè)更通用的模式 UMD,來(lái)解決跨平臺(tái)的問(wèn)題。
diana 庫(kù) 選擇了以 umd 方式進(jìn)行輸出,來(lái)看下 UMD 做了啥:
(function (root, factory) { if (typeof exports === "object" && typeof module === "object") { // UMD 先判斷是否支持 Node.js 的模塊(exports)是否存在,存在則使用 CommonJS 模式 module.exports = factory() } else if (typeof define === "function" && define.amd) { // 接著判斷是否支持 AMD(define是否存在),存在則使用 AMD 方式加載模塊。 define([], factory) } else if (typeof exports === "object") { // CommonJS 的另一種形式 exports["diana"] = factory() } else root["diana"] = factory() // Window })(this, function() { return module })測(cè)試踩坑之路 代碼覆蓋率
單元測(cè)試的代碼覆蓋率統(tǒng)計(jì),是衡量測(cè)試用例好壞的一個(gè)的方法。但凡是線上用的庫(kù),基本上都少不了高質(zhì)量的代碼覆蓋率的檢測(cè)。如下圖為 diana 庫(kù)的測(cè)試覆蓋率展示。
可以看到覆蓋率分為以下 4 種類型,
行覆蓋率(line coverage):是否每一行都執(zhí)行了?
函數(shù)覆蓋率(function coverage):是否每個(gè)函數(shù)都調(diào)用了?
分支覆蓋率(branch coverage):是否每個(gè)if代碼塊都執(zhí)行了?
語(yǔ)句覆蓋率(statement coverage):是否每個(gè)語(yǔ)句都執(zhí)行了?
番外:github 上顯示的覆蓋率是根據(jù)行覆蓋率來(lái)展示的。
最初的版本, 僅僅用到 mocha 進(jìn)行測(cè)試 *.test.js 文件,然后在 codecov 得到測(cè)試覆蓋率。
引人 karma如果僅僅測(cè)試 es5、es6 的語(yǔ)法,其實(shí)用 mocha 就已經(jīng)夠用了,但是涉及到測(cè)試 Dom 操作的語(yǔ)法等就必須建立一個(gè)瀏覽器,在上面進(jìn)行測(cè)試。karma 的作用其實(shí)就是自動(dòng)幫我們建立一個(gè)測(cè)試用的瀏覽器環(huán)境。
為了讓瀏覽器支持 Common.js 規(guī)范,中間用了 karma + browserify,盡管測(cè)試用例都跑通了,但是最后的代碼覆蓋率的文件里只有各個(gè)方法的引用路徑。最后只能又回到 karma + webpack 來(lái),這里又踩到一個(gè)坑,打包編譯JS代碼覆蓋率問(wèn)題,踩了一些坑后,終于實(shí)現(xiàn)了可以查看編譯前代碼的覆蓋率。圖如下:
通過(guò)這幅圖我們能清晰地看到源代碼中測(cè)試用例跑過(guò)各行代碼的次數(shù)(左側(cè)的數(shù)字),以及測(cè)試用例沒(méi)有覆蓋到的代碼(圖中紅色所示)。然后我們就能改善相應(yīng)的測(cè)試用例從而提高測(cè)試覆蓋率。
配置文件,核心部分如下:
module.exports = function(config) { config.set({ files: ["test/index.js"], // 需載入瀏覽器的文件 preprocessors: { // 預(yù)處理 "test/index.js": ["webpack", "coverage"] }, webpack: { module: { rules: [{ test: /.js$/, use: { loader: "sourcemap-istanbul-instrumenter-loader" }, // 這里用 istanbul-instrumenter-loader 插件的 0.0.2 版本,其它版本有坑~ exclude: [/node_modules/, /.spec.js$/], }], } }, coverageReporter: { type: "lcov", // 貌似只能支持這種類型的讀取 dir: "coverage/" }, remapIstanbulReporter: { // 生成 coverage 文件 reports: { "text-summary": null, json: "coverage/coverage.json", lcovonly: "coverage/lcov.info", html: "coverage/html/", } }, reporters: ["progress", "karma-remap-istanbul"], // remap-isbanbul 也報(bào)了一個(gè)未找到 sourcemap 的 error,直接注釋了 remap-istanbul 包的 CoverageTransformer.js 文件的 169 行,以后有機(jī)會(huì)再搗鼓吧。(心累) ... }) }總結(jié)
本文圍繞 diana 庫(kù) 對(duì)造輪子的意義,模塊兼容性,測(cè)試用例進(jìn)行了思考總結(jié)。后續(xù)會(huì)對(duì)該庫(kù)流程自動(dòng)化以及性能上做些分享。
該庫(kù)參考學(xué)習(xí)了很多優(yōu)秀的庫(kù),感謝 underscore、outils、ec-do、30-seconds-of-code 等庫(kù)對(duì)我的幫助。
最后歡迎各位大佬在 issues 盡情吐槽。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/90391.html
摘要:原文地址為了探究按需加載的本質(zhì),選擇了對(duì)先前造的輪子進(jìn)行實(shí)驗(yàn)。下文就來(lái)揭開(kāi)面紗,并動(dòng)手改造項(xiàng)目,最終目標(biāo)是用第二種寫法實(shí)現(xiàn)按需加載,減小打包體積。下面給出種可以按需加載的方案。 原文地址 為了探究按需加載的本質(zhì),選擇了對(duì)先前造的輪子 diana 進(jìn)行實(shí)驗(yàn)。 實(shí)驗(yàn)一:全量引用 import * as _ from diana 打包體積結(jié)果如下: showImg(http://oqhtsc...
摘要:在重新造輪子之前,準(zhǔn)備對(duì)性能優(yōu)化下。最重要的,只寫農(nóng)歷計(jì)算相關(guān)的計(jì)算,其他無(wú)功能,如果需要,通過(guò)本腳本。為除了閏月外的正常月份是大月還是小月,為天,為天。表示閏月是大月還是小月,僅當(dāng)存在閏月的情況下有意義。 工作中有時(shí)需要農(nóng)歷計(jì)算,之前從網(wǎng)上找了個(gè)JS版本的(摘自wannianli.htm,網(wǎng)上導(dǎo)出都是),直接調(diào)用就可以了,非常方便。有優(yōu)點(diǎn)就有缺點(diǎn),該版本文件有點(diǎn)大(20KB以上);有...
摘要:最近,工作中忙于開(kāi)發(fā)一個(gè),主要技術(shù)基于和。我希望這個(gè)滾動(dòng)條長(zhǎng)得好看,可自定義,輕量級(jí),不要依賴于,能和一起用,且支持黑色主題,因?yàn)槲覀兊氖巧钌尘暗摹OM軒偷接行枰娜恕? 最近,工作中忙于開(kāi)發(fā)一個(gè)desktop apps,主要技術(shù)基于 electron 和 angular.js 。開(kāi)發(fā)過(guò)程中,發(fā)現(xiàn)在 Windows 中滾動(dòng)條巨丑無(wú)敵,作為一個(gè)設(shè)計(jì)出身的程序猿,我當(dāng)然不能忍,于是我用下...
摘要:最近,工作中忙于開(kāi)發(fā)一個(gè),主要技術(shù)基于和。我希望這個(gè)滾動(dòng)條長(zhǎng)得好看,可自定義,輕量級(jí),不要依賴于,能和一起用,且支持黑色主題,因?yàn)槲覀兊氖巧钌尘暗?。希望能幫到有需要的人? 最近,工作中忙于開(kāi)發(fā)一個(gè)desktop apps,主要技術(shù)基于 electron 和 angular.js 。開(kāi)發(fā)過(guò)程中,發(fā)現(xiàn)在 Windows 中滾動(dòng)條巨丑無(wú)敵,作為一個(gè)設(shè)計(jì)出身的程序猿,我當(dāng)然不能忍,于是我用下...
閱讀 2694·2023-04-25 17:58
閱讀 2978·2021-11-15 11:38
閱讀 2378·2021-11-02 14:48
閱讀 1184·2021-08-25 09:40
閱讀 1823·2019-08-30 15:53
閱讀 1093·2019-08-30 15:52
閱讀 1031·2019-08-30 13:55
閱讀 2436·2019-08-29 15:21