国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

如何使用 mocha 和 sinon 集成單元測試--單元測試示例及分析(上)

Caicloud / 1026人閱讀

摘要:使用集成單元測試上項目地址安裝依賴測試框架可視化報表覆蓋率替換依賴斷言命令命令命令執行單元測試,并打開測試報告頁面和覆蓋率頁面執行生成單元測試覆蓋率并打開執行單個單元測試文

使用 mocha 集成單元測試(上)
項目地址:https://github.com/Jay-tian/j...
安裝依賴
yarn add jquery mocha  mochawesome  istanbul  sinon chai jsdom decache babel-cli babel-core babel-preset-es2015 babel-plugin-module-resolver babel-istanbul  

mocha:測試框架
mochawesome:可視化報表
istanbul:覆蓋率
sinon:替換依賴
chai:斷言

scripts 命令

命令

  "scripts": {
    "test": "mocha --timeout 5000 --recursive --reporter mochawesome --require babel-core/register tests/src && open mochawesome-report/mochawesome.html && npm run test:cover",
    "test:cover": "babel-node ./node_modules/.bin/babel-istanbul cover _mocha -- tests/src/* -R spec --recursive && open coverage/lcov-report/index.html",
    "test:s": "mocha --recursive --require babel-core/register  --timeout 5000"
  }

test 命令:執行單元測試,并打開測試報告頁面和覆蓋率頁面
test:cover 執行生成單元測試覆蓋率并打開
test:s 執行單個單元測試文件

參數解析

--timeout 5000 超時設置
--recursive 包含子目錄
--reporter mochawesome 通過mochawesome生成報表
--require babel-core/register 通過babel轉譯es6語法
tests/src 單元測試目錄路徑
open mochawesome-report/mochawesome.html 打開頁面

測試含有jQuery的代碼 初始化Jquery環境
let { JSDOM } = require("jsdom");
let dom = new JSDOM(``,{
    url: "http://127.0.0.1",
    referrer: "http://127.0.0.1",
    contentType: "text/html",
    userAgent: "Mellblomenator/9000",
    includeNodeLocations: true,
});
global.window = dom.window;
global.$ = require("jquery");
測試click事件
const { demo1 } = require("../../src/demo1.js");
const assert = require("chai").assert;
describe("demo1", function() {
  it("jquery click test", function() {
    demo1($("body"));
    assert.equal($("body").hasClass("hide"), false);
    $("body").trigger("click");
    assert.equal($("body").hasClass("hide"), true);
  });
});
運行結果

以上測試了,點擊元素時,給該元素添加一個‘hide’類的方法
模擬jquery環境和觸發click事件

測試post事件

由于初始化jquery環境比較通用,我們把它放到工具類去引用

utils.js
const decache = require("decache");
let { JSDOM } = require("jsdom");
exports.initJquery = function(html, params = {}){
    params = Object.assign({
        url: "http://127.0.0.1",
        referrer: "http://127.0.0.1",
        contentType: "text/html",
        userAgent: "Mellblomenator/9000",
        includeNodeLocations: true,
    }, params);
    let dom = new JSDOM(`${html}`, params);

    global.window = dom.window;
    decache("jquery");
    global.$ = require("jquery");
}

因為node環境中,require會有緩存,導致不同的單元測試間的初始環境不一致,需要手動清除緩存

 decache("jquery");
test.demo2.js
import post from "../../src/demo2.js"; 
const utils = require("./../utils");
const sinon = require("sinon");
require("./../utils");
describe("demo2", function() {
    before(function() {
        utils.initJquery("");
    });
    
    it("jquery post", function() {
        let stubPost = sinon.stub($, "post");
        let expectedUrl = "/demo2";
        let expectedParams = {"a": "abc"};
        post();
        sinon.assert.calledWith(stubPost, expectedUrl, expectedParams);
        stubPost.restore();
    });
});

restore()操作 將會復原被替換的對象
mocha 有四個鉤子方法
before 在所有的單元測試運行前運行一次
after 在所有的單元測試運行結束運行一次
beforeEach 在每一個的單元測試運行前運行一次
afterEach 在每一個的單元測試運行后運行一次

測試ajax demo3.js
export default function() {
    $.ajax({
    type: "GET",
    url: null,
    async: true,
    promise: true,
    dataType: "json",
    beforeSend(request) {
    }
  });
}
test.demo3.js
import ajax from "../../src/demo3.js"; 
const utils = require("./../utils");
const sinon = require("sinon");
require("./../utils");
describe("demo3", function() {
    before(function() {
        utils.initJquery("");
    });
    
    it("jquery ajax", function() {
        let stubAjax = sinon.stub($, "ajax");
        let expectedParams = {
            type: "GET",
            url: null,
            async: true,
            promise: true,
            dataType: "json"
        };
        ajax();
        sinon.assert.calledWithMatch(stubAjax, expectedParams);
        stubAjax.restore();
    });
});

這里我們使用calledWithMatch斷言參數,該方法可以斷言傳入的參數是否正確,不需要傳入所有的參數

測試異步代碼 demoe4.js
export default function() { 
    $("#demo4").hide();
    setTimeout(
        function(){
            $("#demo4").show();
        }, 1000);
}
import demo4 from "../../src/demo4.js"; 
const utils = require("./../utils");
const sinon = require("sinon");
const assert = require("chai").assert;
require("./../utils");
describe("asynchronous code", function() {
    let clock;
    before(function () { 
        utils.initJquery("
"); }); it("test by setTimeout", function(done) { let $demo = $("#demo4"); demo4(); assert.equal($demo.css("display"), "none"); let test = function() { assert.equal($demo.css("display"), "block"); // 這里的done告知這個單元測試結束了,保證不影響其他單元測試 done(); }; setTimeout(test, 1001); }); it("test by sinon", function() { //當利用了useFakeTimers后,事件將會停止 clock = sinon.useFakeTimers(); let $demo = $("#demo4"); //運行demo4前,元素還是顯示的 assert.equal($demo.css("display"), "block"); demo4(); //運行demo4完,元素隱藏了 assert.equal($demo.css("display"), "none"); //時間穿梭101ms秒,定時器代碼還未執行,所以元素還是隱藏的 clock.tick(101); assert.equal($demo.css("display"), "none"); //時間再穿梭900ms秒,就到達了1001ms后,定時器代碼執行了,所以元素現在顯示了 clock.tick(900); assert.equal($demo.css("display"), "block"); //恢復時間 clock.restore(); }); });

第一個單元測試利用了 setTimeout 去測試異步代碼
第二個單元測試利用了 sinon 的時空穿梭器去測試異步代碼
結果如圖所示

第一個單元測試花了1035ms
而第二個單元測試幾乎沒有花費多少時間

所以異步代碼編寫單元測試時,第二個單元測試寫法更優

需要測試的代碼包含其他負責業務邏輯時 demo5.js
const demo5require = require("./demo5.require.js");

export default function() { 
    if(demo5require.a() == "a") {
        return 1;
    } else {
        return 2;
    }
}
test.demo5.js
import demo5 from "../../src/demo5.js"; 
const utils = require("./../utils");
const sinon = require("sinon");
const assert = require("chai").assert;

describe("demo5", function() {
    before(function () { 
        utils.initJquery("");
    });
    it("test", function() {
        assert.equal(demo5(), 1);
        const demo5require = require("../../src/demo5.require.js");
        let stub = sinon.stub(demo5require, "a").returns("b");
        assert.equal(demo5(), 2);
        stub.restore();
    });
});

此時demo5依賴其他模塊,我們就可以替換demo5require的方法,并指定返回值,這樣就不用關系依賴的模塊做了什么業務。
測試結束,復原被替換的對象

webpack環境編寫單元測試

webpack中會有設置別名的情況,這樣單元測試有可能引入的模塊的路徑有誤,這里我們可以使用babel-plugin-module-resolver進行別名的替換

.babelrc
{
  "presets": ["es2015"],
  "plugins": [
    ["module-resolver", {
      "root": ["./"],
      "alias": {
         "common":""
      }
    }]
  ]
}
運行結果

執行命令

npm run test

如圖


最佳實踐總結

文件名以及路徑的定義如下,這樣定義規范了路徑的書寫,便于文件的查找

/a/b/c/demo.js //待測試文件
/tests/a/b/c/test.demo.js //單元測試文件

一個單元測試文件測試一個js文件

一個describe測試一個方法

一個it 測試一個方法中一個邏輯,這樣保證一個測試只驗證一個行為

使用sinon隔離外部調用

使用before或beforeEach 初始環境

使用after或afterEach 清空或還原環境,不同單元測試互不影響,狀態不共享

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/93807.html

相關文章

  • 【Node Hero】9. Node.js 單元測試

    摘要:基本上,測試金字塔描述你應該編寫單元測試集成測試和端到端測試。集成測試要比端到端測試多,單元測試甚至要更多一些。應用程序單元測試編寫單元測試,是為了看看給定的模塊單元是否工作。 本文轉載自:眾成翻譯譯者:網絡埋伏紀事鏈接:http://www.zcfy.cc/article/1754原文:https://blog.risingstack.com/node-hero-node-js-un...

    104828720 評論0 收藏0
  • mocha、chai、sinonistanbul實現100%單元測試覆蓋率

    摘要:加上測試覆蓋率檢查,就能夠提供足夠的信息,來斷言代碼的行為是否符合期望。測試的相關技術是程序的代碼覆蓋率工具,以土耳其最大城市伊斯坦布爾命名。 showImg(https://segmentfault.com/img/remote/1460000010260434); 敏捷軟件開發中,最重要實踐的就是測試驅動開發,在單元測試層面,我們試著實現一個重要的指標就是測試覆蓋率。測試覆蓋率衡量...

    Yuanf 評論0 收藏0
  • 前端單元測試初探

    摘要:本文只討論單測的范疇,對集成測試有興趣的話,可以看下的集成測試代碼。前端單測現狀測試本質上就是假定一個輸入,然后判斷得到預期的輸出。 原文發于我的博客:https://github.com/hwen/blogS... 要不要寫單測? 關于這個 cnode 上就有個很有意思的討論 做個調查,你的 Node 應用有寫單測嗎? 看完這個應該會有結論?如果沒有,就回帖跟別人探討下~ 測試 測試...

    isLishude 評論0 收藏0
  • 使用karma+mocha+chai+sinon+@vue/test-utils為你的組件庫增加單元

    摘要:但是,項目中的一些公共封裝,比如公共的組件公用的功能模塊等是可以使用單元測試的。因此特為組件庫引入單元測試,目的在于能減少組件的,避免重復的發布不必要的包。 項目github地址:https://github.com/yuanalina/installAsRequired這里必須要提前說明,前端項目的單元測試不是必須的,特別是業務型項目,增加單元測試反而會成為累贅,增加開發成本且無意義...

    happen 評論0 收藏0
  • Ajax單元測試傻瓜教程

    摘要:原文出處單元測試傻瓜教程請求經常容易發生錯誤,客戶端發送的數據出問題,服務器端返回的數據有誤都會導致請求錯誤。設置在我們開始單元測試之前,我們需要安裝幾個必須的工具。我們將用它來向你們展示如何對進行單元測試。 原文出處 :AJAX單元測試傻瓜教程 Ajax 請求經常容易發生錯誤,客戶端發送的數據出問題,服務器端返回的數據有誤都會導致 Ajax 請求錯誤。你不能保證與服務器的連接總是工作...

    30e8336b8229 評論0 收藏0

發表評論

0條評論

Caicloud

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<