成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專欄INFORMATION COLUMN

提高代碼質(zhì)量——使用Jest和Sinon給已有的代碼添加單元測(cè)試

voyagelab / 1654人閱讀

摘要:現(xiàn)在,我們可以使用單元測(cè)試來(lái)提高自己的代碼質(zhì)量。它在單元測(cè)試的編寫中通常用來(lái)模擬等相關(guān)請(qǐng)求。通過(guò)這篇文章,你應(yīng)該學(xué)會(huì)了如何針對(duì)已有代碼從零開始編寫一套完整的單元測(cè)試用例。

概述

在日常的功能開發(fā)中,我們的代碼測(cè)試都依賴于自己或者QA進(jìn)行測(cè)試。這些操作不僅費(fèi)時(shí)費(fèi)力,而且還依賴開發(fā)者自身的驅(qū)動(dòng)。在開發(fā)一些第三方依賴的庫(kù)時(shí),我們也沒(méi)有辦法給第三方提供完整的代碼質(zhì)量報(bào)告。

現(xiàn)在,我們可以使用單元測(cè)試來(lái)提高自己的代碼質(zhì)量。下面,我將自己在使用Jest和Sinon.js配置和編寫單元測(cè)試中的收獲的經(jīng)驗(yàn)和踩到的坑進(jìn)行總結(jié),根據(jù)從零開始配置和編寫單元測(cè)試這一條線來(lái)進(jìn)行分享。

通過(guò)本文,你可以解決以下問(wèn)題:

Jest與Sinon.js是什么?

如何配置Jest與Sinon.js,從而編寫單元測(cè)試?

如何解決進(jìn)行單元測(cè)試中遇到的常見問(wèn)題?

Jest與Sinon.js是什么

Jest是FaceBook推出的一個(gè)針對(duì)JavaScript進(jìn)行單元測(cè)試的庫(kù),它提供了斷言、函數(shù)模擬等API來(lái)對(duì)你自己編寫的業(yè)務(wù)邏輯代碼進(jìn)行測(cè)試后。

Sinon.js是一個(gè)用來(lái)做獨(dú)立測(cè)試和模擬的JavaScript庫(kù)。它在單元測(cè)試的編寫中通常用來(lái)模擬HTTP等相關(guān)請(qǐng)求。

為什么沒(méi)有用其他的單元測(cè)試框架

在最開始的框架選擇中,我先嘗試了能夠并行測(cè)試,大大提高單元測(cè)試速度的ava框架。它能滿足日常的普通需求如utils工具集的測(cè)試,也能夠配置Sinon.js來(lái)進(jìn)行HTTP模擬測(cè)試。

但是,在處理webpack alias的問(wèn)題時(shí),通過(guò)官方issue中的極其復(fù)雜的配置也沒(méi)有能夠解決出現(xiàn)Cannot find module的問(wèn)題(其中一個(gè)解決此問(wèn)題的插件babel-plugin-webpack-loaders中竟然是推薦直接使用Jest,囧)。

而在Jest中,可以很方便的通過(guò)一些簡(jiǎn)單配置,就能夠識(shí)別在文件中使用的webpack alias,相關(guān)的具體方法將會(huì)在后面章節(jié)進(jìn)行具體描述。

而對(duì)于其他的測(cè)試框架如:Mocha或者Chai等,沒(méi)有進(jìn)行具體的了解,因此在這里不多做評(píng)價(jià)。

如何配置Jest與Sinon.js,從而編寫單元測(cè)試? Jest配置 安裝依賴包

需要使用Jest,首先你需要進(jìn)行安裝,執(zhí)行以下命令:

npm install jest -D

如果你的項(xiàng)目中存在.babelrc文件(使用了babel 6)時(shí),不論你測(cè)試的代碼是否通過(guò)babel進(jìn)行編譯,你都需要安裝額外的幾個(gè)包:

npm install babel-jest babel-core regenerator-runtime -D

如果你使用的是babel 7,則需要安裝下面幾個(gè)包:

npm install babel-jest "babel-core@^7.0.0-0" @babel/core regenerator-runtime -D
package.json文件配置

在安裝完成依賴包以后,如果你有相關(guān)的jest配置項(xiàng)需要設(shè)置,你還可以在package.json文件中配置如下字段:

{
  "jest": {
    
  }
}

.babelrc文件只需要保存之前的配置,不需要做任何修改即可生效。

Sinon.js配置 依賴包安裝

安裝配置完了Jest,讓我們來(lái)看下Sinon.js。需要使用Sinon.js,我們首先需要進(jìn)行安裝:

npm install sinon -D

配置完成后,需要在使用的地方進(jìn)行引入,如下所示:

const sinon = require("sinon");

在我的項(xiàng)目中,主要是使用Sinon.js來(lái)模擬HTTP請(qǐng)求。在Sinon.js的文檔中,有專門關(guān)于XMLHttpRequest對(duì)象的模擬的章節(jié),在下一章中,我們將會(huì)針對(duì)項(xiàng)目中sinon.js的使用進(jìn)行簡(jiǎn)單的介紹。

編寫單元測(cè)試

在本章中,我們會(huì)針對(duì)如何編寫單元測(cè)試文件進(jìn)行一個(gè)具體的講解,其中包含:

同步函數(shù)測(cè)試

異步函數(shù)測(cè)試

HTTP測(cè)試

同時(shí),我們會(huì)對(duì)當(dāng)中使用到的Jest和Sinon.js的API會(huì)進(jìn)行簡(jiǎn)單介紹,如果需要使用其他的API,可以自行閱讀Jest和Sinon.js的文檔。

通過(guò)上面三類測(cè)試,我們基本能夠覆蓋現(xiàn)有項(xiàng)目中的所有代碼。

同步函數(shù)測(cè)試

同步函數(shù)的測(cè)試過(guò)程是這幾個(gè)中最簡(jiǎn)單的一部分,我們可以測(cè)試函數(shù)返回值,也能夠測(cè)試傳入的高階函數(shù)。下面我們通過(guò)一個(gè)具體的例子來(lái)看下。

源代碼文件,一個(gè)純函數(shù):

// user.js
export default function(obj) {
    return "hjava";
}

export function handleUserData(callback) {
    callback("hjava");
}

針對(duì)上面的源代碼文件編寫的一個(gè)單元測(cè)試文件:

// user.test.js
import userFunc, {handleUserData} from "./user";

// test是一個(gè)注冊(cè)的全局方法
test("user", () => {
    expect(userFunc()).toBe("hjava"); // 判斷userFunc的執(zhí)行結(jié)果等于"hjava"
    
    let callback = jest.fn(); // jest是一個(gè)注冊(cè)的全局變量
    handleUserData(callback);

    expect(callback.mock.calls.length).toBe(1); // 判斷callback函數(shù)被調(diào)用了一次
    expect(callback.mock.calls[0][0]).toBe("hjava"); // 判斷了callback函數(shù)的第一次被調(diào)用的第一個(gè)參數(shù)為"hjava"
});

從上面的示例中我們可以看到,針對(duì)同步的純函數(shù),我們可以通過(guò)很簡(jiǎn)單的單元測(cè)試模型來(lái)驗(yàn)證它的功能。

異步函數(shù)測(cè)試

異步函數(shù)主要分為兩種——Callback方式和Promise方式。這兩種方式都很簡(jiǎn)單,下面我們對(duì)兩種方式進(jìn)行具體的介紹。詳細(xì)內(nèi)容可以見Jest文檔中的測(cè)試異步代碼。

Callback方式
// user.js
export default function(callback) {
    setTimeout(()=>{
        callback({username: "hjava"});
    }, 1000);
}
// user.test.js
import userFunc from "./user";

test("user", () => {
    userFunc((data) => {
        expect(data).toEqual({username: "hjava"}); // 對(duì)象比較用beEqual()
    });
});
Promise方式
// user.js
export default function(callback) {
    return Promise.resolve({username: "hjava"});
}
// user.test.js
import userFunc from "./user";

test("user", () => {
    userFunc().then((data) => {
        expect(data).toEqual({username: "hjava"});
    });
});
HTTP測(cè)試

在測(cè)試HTTP請(qǐng)求相關(guān)參數(shù)的過(guò)程中,我們需要模擬XMLHttpRequest對(duì)象,從而攔截相關(guān)的HTTP請(qǐng)求,獲取請(qǐng)求數(shù)據(jù)。正好Sinon.js能夠做到這一點(diǎn)。下面我們通過(guò)一個(gè)示例來(lái)看下相關(guān)的邏輯:

// user.js
export default function(callback) {
    this.sendRequest("/user/get", callback); // 發(fā)送請(qǐng)求來(lái)獲取用戶數(shù)據(jù),成功后執(zhí)行callback回調(diào)函數(shù)
}
// user.test.js
import Sinon from "sinon";
import userFunc from "user";

let XHR;
let requests = [];
// beforeEach是Jest提供的函數(shù),在每個(gè)測(cè)試執(zhí)行前都會(huì)執(zhí)行一次
beforeEach(() => {
    XHR = sinon.useFakeXMLHttpRequest(); //創(chuàng)建一個(gè)模擬的XMLHttpRequest對(duì)象

    XHR.onCreate = function (xhr) {
        requests.push(xhr);
    };
});

// afterEach是Jest提供的函數(shù),在每個(gè)測(cè)試執(zhí)行后都會(huì)執(zhí)行一次
afterEach(() => {
    XHR.restore();
});

test("user", () => {
    let callback = jest.fn();

    HTTPCommon.deleteRemoteSession({
        data: {},
        success: callback
    });

    expect(requests.length).toBe(1);

    requests[0].respond(200, {"Content-Type": "application/json"}, "hjava"); // 模擬返回值

    expect(callback.mock.calls[0][0]).toBe("hjava");
});
如何解決進(jìn)行單元測(cè)試中遇到的常見問(wèn)題?

在本章中,我們總結(jié)了如下問(wèn)題來(lái)進(jìn)行介紹,希望大家再遇到相同問(wèn)題時(shí)能夠快速解決:

如何統(tǒng)計(jì)Jest單元測(cè)試覆蓋率

如何設(shè)置單元測(cè)試文件不使用本地的babel配置

如何設(shè)置單元測(cè)試文件使用本地的babel配置

如何處理代碼中引用的webpack alias問(wèn)題

如何統(tǒng)計(jì)單元測(cè)試覆蓋率?

不像ava一樣,需要使用syc來(lái)進(jìn)行計(jì)算,Jest內(nèi)置了統(tǒng)計(jì)單元測(cè)試覆蓋率的工具,只需要簡(jiǎn)單配置即可達(dá)到相關(guān)的要求。具體配置如下:

// package.json
{
  "jest": {
    "collectCoverage": true, // 是否開啟統(tǒng)計(jì)單元測(cè)試覆蓋率
    "collectCoverageFrom": [ // 指定統(tǒng)計(jì)單元測(cè)試覆蓋率文件
      "**/src/**.js"
    ],
  }
}
如何設(shè)置單元測(cè)試文件不使用ES2015配置

如果你的項(xiàng)目中有.babelrc文件,而你不希望單元測(cè)試文件受到babel文件的影響,你可以在jest的配置項(xiàng)中增加transform字段,具體配置如下:

// package.json
{
  "jest": {
    "transform": {}
  }
}
如何設(shè)置單元測(cè)試使用ES2015配置

如果你的單元測(cè)試文件中需要使用ES2015后通過(guò)babel來(lái)進(jìn)行編譯,那么需要對(duì).babelrc文件的配置進(jìn)行部分修改。

如果你之前在.babelrc文件中,把modules字段設(shè)置為false,那么你需要在test環(huán)境下重新開啟,具體代碼如下:

// .babelrc
{
  "presets": [["env", {"modules": false}]],
  "env": {
    "test": {
      "presets": [["env"]]
    }
  }
}

如果你使用的是babel 7的話(安裝時(shí)多安裝過(guò)相關(guān)依賴包),你需要設(shè)置的presets字段的值應(yīng)該為@babel/env,具體代碼如下:

// .babelrc
{
  "presets": [["env", {"modules": false}]],
  "env": {
    "test": {
      "presets": [["@babel/env"]]
    }
  }
}
如何處理代碼中引用的webpack alias問(wèn)題

如果我們?cè)陧?xiàng)目中使用了webpack,那么我們很大概率會(huì)使用到alias相關(guān)屬性來(lái)定義路徑。但是,在單元測(cè)試框架中,它并不能夠識(shí)別這種路徑,就會(huì)出現(xiàn)Cannot find module "xxx" from "yyy"的報(bào)錯(cuò)。

不像ava框架需要安裝插件和進(jìn)行復(fù)雜的配置,我們只需要在Jest中配置moduleNameMapper屬性即可滿足需求。具體示例如下:

// webpack.config.js
{
    alias: {
        "@__dir":process.cwd()
    }
}
//package.json
{
    "jest": {
        "moduleNameMapper": {
        "@__dir(.*)$": "$1" //正則匹配方式,對(duì)應(yīng)webpack alias
        }
    }
}
總結(jié)

編寫測(cè)試是一個(gè)很好的習(xí)慣。

很多人經(jīng)常都說(shuō)要對(duì)自己的代碼進(jìn)行質(zhì)量監(jiān)控,但是又不知道該如何下手。通過(guò)這篇文章,你應(yīng)該學(xué)會(huì)了如何針對(duì)已有代碼從零開始編寫一套完整的單元測(cè)試用例。

如果有任何疑問(wèn),歡迎留言或者私信進(jìn)行溝通與交流。

關(guān)于Jest是如何測(cè)試JavaScript代碼以及Sinon是如何模擬XMLHttpRequest請(qǐng)求的,我們將會(huì)在后面幾篇博客中給大家?guī)?lái)相關(guān)的源碼解析,有興趣的同學(xué)可以關(guān)注我,留意后續(xù)的文章。

附錄

Jest

Sinon.js

ava

ava關(guān)于配置解決webpack alias的issue

Mocha

Chai

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/94392.html

相關(guān)文章

  • 如何模擬一個(gè)XMLHttpRequest請(qǐng)求用于單元測(cè)試——nise源碼閱讀與分析

    摘要:概述在我們進(jìn)行單元測(cè)試的過(guò)程中,如果我們需要對(duì)一些接口進(jìn)行相關(guān)的業(yè)務(wù)測(cè)試,那么我們就需要來(lái)模擬請(qǐng)求的發(fā)送與響應(yīng),否則我們就無(wú)法完成測(cè)試的閉環(huán)。我們?cè)偻ㄟ^(guò)記錄的數(shù)據(jù),組合其他的單元測(cè)試框架來(lái)對(duì)業(yè)務(wù)代碼進(jìn)行測(cè)試。 概述 在我們進(jìn)行單元測(cè)試的過(guò)程中,如果我們需要對(duì)一些HTTP接口進(jìn)行相關(guān)的業(yè)務(wù)測(cè)試,那么我們就需要來(lái)模擬HTTP請(qǐng)求的發(fā)送與響應(yīng),否則我們就無(wú)法完成測(cè)試的閉環(huán)。 目前,有許許多多...

    KevinYan 評(píng)論0 收藏0
  • 前端組件的測(cè)試

    摘要:的配置文件是為了解析那些需要測(cè)試的源文件相關(guān)的文件,然后再給的單元測(cè)試用例去識(shí)別。其作用是僅僅渲染至虛擬節(jié)點(diǎn),不會(huì)返回真實(shí)的節(jié)點(diǎn),能極大提高測(cè)試性能。 為解放勞動(dòng)力,發(fā)展生產(chǎn)力 測(cè)試有了這般變化: 鼠標(biāo)點(diǎn)擊手動(dòng)測(cè)試 -> 用腳本模擬,自動(dòng)化測(cè)試 Vue中的組件測(cè)試 需要安裝的包 全局安裝:babel、mocha、karma 其他局部安裝的包在下面的【測(cè)試環(huán)境搭建】最下方配置文件中給出...

    haobowd 評(píng)論0 收藏0
  • Web 前端單元測(cè)試到底要怎么寫?看這一篇就夠了

    摘要:隨著應(yīng)用的復(fù)雜程度越來(lái)越高,很多公司越來(lái)越重視前端單元測(cè)試。最后我們可以利用覆蓋率來(lái)看下用例的覆蓋程度是否足夠一般來(lái)說(shuō)不用刻意追求,根據(jù)實(shí)際情況來(lái)定單元測(cè)試是測(cè)試驅(qū)動(dòng)開發(fā)的基礎(chǔ)。 隨著 Web 應(yīng)用的復(fù)雜程度越來(lái)越高,很多公司越來(lái)越重視前端單元測(cè)試。我們看到的大多數(shù)教程都會(huì)講單元測(cè)試的重要性、一些有代表性的測(cè)試框架 api 怎么使用,但在實(shí)際項(xiàng)目中單元測(cè)試要怎么下手?測(cè)試用例應(yīng)該包含哪...

    lastSeries 評(píng)論0 收藏0
  • mocha、chai、sinonistanbul實(shí)現(xiàn)100%單元測(cè)試覆蓋率

    摘要:加上測(cè)試覆蓋率檢查,就能夠提供足夠的信息,來(lái)斷言代碼的行為是否符合期望。測(cè)試的相關(guān)技術(shù)是程序的代碼覆蓋率工具,以土耳其最大城市伊斯坦布爾命名。 showImg(https://segmentfault.com/img/remote/1460000010260434); 敏捷軟件開發(fā)中,最重要實(shí)踐的就是測(cè)試驅(qū)動(dòng)開發(fā),在單元測(cè)試層面,我們?cè)囍鴮?shí)現(xiàn)一個(gè)重要的指標(biāo)就是測(cè)試覆蓋率。測(cè)試覆蓋率衡量...

    Yuanf 評(píng)論0 收藏0
  • 前端單元測(cè)試 實(shí)現(xiàn)教程 mocha + mochawesome + istanbul + sinon

    摘要:為什么要寫單元測(cè)試減少提高代碼質(zhì)量,保證你的代碼是可測(cè)試的放心重構(gòu)當(dāng)你每個(gè)方法都寫了單元測(cè)試的時(shí)候,你每一個(gè)改動(dòng)都會(huì)影響相應(yīng)的單元測(cè)試,這樣你不用費(fèi)盡心思的考慮哪里會(huì)有影響,特別是復(fù)雜項(xiàng)目或非核心功能不易被測(cè)試到,從而導(dǎo)致的產(chǎn)生。 為什么要寫單元測(cè)試 減少bug 提高代碼質(zhì)量,保證你的代碼是可測(cè)試的 放心重構(gòu) 當(dāng)你每個(gè)方法都寫了單元測(cè)試的時(shí)候,你每一個(gè)改動(dòng)都會(huì)影響相應(yīng)的單元測(cè)試,這...

    AaronYuan 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

voyagelab

|高級(jí)講師

TA的文章

閱讀更多
最新活動(dòng)
閱讀需要支付1元查看
<