成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

在Nodejs中貫徹單元測(cè)試

enali / 2912人閱讀

摘要:原文鏈接在中貫徹單元測(cè)試在團(tuán)隊(duì)合作中,你寫好了一個(gè)函數(shù),供隊(duì)友使用,跑去跟你的隊(duì)友說,你傳個(gè)值進(jìn)去,他就會(huì)返回結(jié)果了。如果你也為社區(qū)貢獻(xiàn)過,想更多人使用的話,加上單元測(cè)試吧,讓你的值得別人信賴。

原文鏈接:BlueSun | 在Nodejs中貫徹單元測(cè)試

在團(tuán)隊(duì)合作中,你寫好了一個(gè)函數(shù),供隊(duì)友使用,跑去跟你的隊(duì)友說,你傳個(gè)A值進(jìn)去,他就會(huì)返回B結(jié)果了。過了一會(huì),你隊(duì)友跑過來說,我傳個(gè)A值卻返回C結(jié)果,怎么回事?你丫的有沒有測(cè)試過?。?/p>

大家一起寫個(gè)項(xiàng)目,難免會(huì)有我要寫的函數(shù)里面依賴別人的函數(shù),但是這個(gè)函數(shù)到底值不值得信賴?單元測(cè)試是衡量代碼質(zhì)量的一重要標(biāo)準(zhǔn),縱觀Github的受歡迎項(xiàng)目,都是有test文件夾,并且buliding-pass的。如果你也為社區(qū)貢獻(xiàn)過module,想更多人使用的話,加上單元測(cè)試吧,讓你的module值得別人信賴。

要在Nodejs中寫單元測(cè)試的話,你需要知道用什么測(cè)試框架,怎么測(cè)試異步函數(shù),怎么測(cè)試私有方法,怎么模擬測(cè)試環(huán)境,怎么測(cè)試依賴HTTP協(xié)議的web應(yīng)用,需要了解TDD和BDD,還有需要提供測(cè)試的覆蓋率。

本文的示例代碼會(huì)備份到 Github : unittest-demo

目錄

測(cè)試框架

斷言庫(kù)

需求變更

異步測(cè)試

異常測(cè)試

測(cè)試私有方法

測(cè)試Web應(yīng)用

覆蓋率

使用Makefile把測(cè)試串起來

持續(xù)集成,Travis-cli

一些觀點(diǎn)

彩蛋

整理

測(cè)試框架

Nodejs的測(cè)試框架還用說?大家都在用,Mocha。

Mocha 是一個(gè)功能豐富的Javascript測(cè)試框架,它能運(yùn)行在Node.js和瀏覽器中,支持BDD、TDDQUnit、Exports式的測(cè)試,本文主要示例是使用更接近與思考方式的BDD,如果了解更多可以訪問Mocha的官網(wǎng)

測(cè)試接口

Mocha的BDD接口有:

describe()

it()

before()

after()

beforeEach()

afterEach()

安裝

npm install mocha -g

編寫一個(gè)穩(wěn)定可靠的模塊

模塊具備limit方法,輸入一個(gè)數(shù)值,小于0的時(shí)候返回0,其余正常返回

exports.limit = function (num) {
  if (num < 0) {
    return 0;
  }
  return num;
};
目錄分配

lib,存放模塊代碼的地方

test,存放單元測(cè)試代碼的地方

index.js,向外導(dǎo)出模塊的地方

package.json,包描述文件

測(cè)試
var lib = require("index");

describe("module", function () {
  describe("limit", function () {
    it("limit should success", function () {
      lib.limit(10);
    });
  });
});
結(jié)果

在當(dāng)前目錄下執(zhí)行mocha

$ mocha

  ?

  ? 1 test complete (2ms)
斷言庫(kù)

上面的代碼只是運(yùn)行了代碼,并沒有對(duì)結(jié)果進(jìn)行檢查,這時(shí)候就要用到斷言庫(kù)了,Node.js中常用的斷言庫(kù)有:

should.js

expect.js

chai

加上斷言

使用should庫(kù)為測(cè)試用例加上斷言

it("limit should success", function () {
  lib.limit(10).should.be.equal(10);
});
需求變更

需求變更啦:?limit這個(gè)方法還要求返回值大于100時(shí)返回100。

針對(duì)需求重構(gòu)代碼之后,正是測(cè)試用例的價(jià)值所在了,

它能確保你的改動(dòng)對(duì)原有成果沒有造成破壞。

但是,你要多做的一些工作的是,需要為新的需求編寫新的測(cè)試代碼。

異步測(cè)試 測(cè)試異步回調(diào)

lib庫(kù)中新增async函數(shù):

exports.async = function (callback) {
  setTimeout(function () {
    callback(10);
  }, 10);
};    

測(cè)試異步代碼:

describe("async", function () {
  it("async", function (done) {
    lib.async(function (result) {
      done();
    });
  });
});
測(cè)試Promise

使用should提供的Promise斷言接口:

finally | eventually

fulfilled

fulfilledWith

rejected

rejectedWith

then

測(cè)試代碼

describe("should", function () {
  describe("#Promise", function () {
    it("should.reject", function () {
      (new Promise(function (resolve, reject) {
        reject(new Error("wrong"));
      })).should.be.rejectedWith("wrong");
    });

    it("should.fulfilled", function () {
      (new Promise(function (resolve, reject) {
        resolve({username: "jc", age: 18, gender: "male"})
      })).should.be.fulfilled().then(function (it) {
          it.should.have.property("username", "jc");
        })
    });
  });
});
異步方法的超時(shí)支持

Mocha的超時(shí)設(shè)定默認(rèn)是2s,如果執(zhí)行的測(cè)試超過2s的話,就會(huì)報(bào)timeout錯(cuò)誤。

可以主動(dòng)修改超時(shí)時(shí)間,有兩種方法。

命令行式

mocha -t 10000

API式
describe("async", function () {
  this.timeout(10000);
  it("async", function (done) {
    lib.async(function (result) {
      done();
    });
  });
});

這樣的話async執(zhí)行時(shí)間不超過10s,就不會(huì)報(bào)錯(cuò)timeout錯(cuò)誤了。

異常測(cè)試

異常應(yīng)該怎么測(cè)試,現(xiàn)在有getContent方法,他會(huì)讀取指定文件的內(nèi)容,但是不一定會(huì)成功,會(huì)拋出異常。

exports.getContent = function (filename, callback) {
  fs.readFile(filename, "utf-8", callback);
};

這時(shí)候就應(yīng)該模擬(mock)錯(cuò)誤環(huán)境了

簡(jiǎn)單Mock
describe("getContent", function () {
  var _readFile;
  before(function () {
    _readFile = fs.readFile;
    fs.readFile = function (filename, encoding, callback) {
      process.nextTick(function () {
        callback(new Error("mock readFile error"));
      });
    };    
  });
  // it();
  after(function () {
    // 用完之后記得還原。否則影響其他case
    fs.readFile = _readFile;
  })
});
Mock庫(kù)

Mock小模塊:muk ,略微優(yōu)美的寫法:

var fs = require("fs");
var muk = require("muk");

before(function () {
  muk(fs, "readFile", function(path, encoding, callback) {
    process.nextTick(function () {
      callback(new Error("mock readFile error"));
    });
  });
});
// it();
after(function () {
  muk.restore();
});
測(cè)試私有方法

針對(duì)一些內(nèi)部的方法,沒有通過exports暴露出來,怎么測(cè)試它?

function _adding(num1, num2) {
  return num1 + num2;
}
通過rewire導(dǎo)出方法

模塊:rewire

it("limit should return success", function () {
  var lib = rewire("../lib/index.js");
  var litmit = lib.__get__("limit");
  litmit(10);
});
測(cè)試Web應(yīng)用

在開發(fā)Web項(xiàng)目的時(shí)候,要測(cè)試某一個(gè)API,如:/user,到底怎么編寫測(cè)試用例呢?

使用:supertest

var express = require("express");
var request = require("supertest");
var app = express();

// 定義路由
app.get("/user", function(req, res){
  res.send(200, { name: "jerryc" });
});

describe("GET /user", function(){
  it("respond with json", function(done){
    request(app)
      .get("/user")
      .set("Accept", "application/json")
      .expect("Content-Type", /json/)
      .expect(200)
      .end(function (err, res) {
        if (err){
          done(err);
        }
        res.body.name.should.be.eql("jerryc");
        done();
      })
  });
});
覆蓋率

測(cè)試的時(shí)候,我們常常關(guān)心,是否所有代碼都測(cè)試到了。

這個(gè)指標(biāo)就叫做"代碼覆蓋率"(code coverage)。它有四個(gè)測(cè)量維度。

行覆蓋率(line coverage):是否每一行都執(zhí)行了?

函數(shù)覆蓋率(function coverage):是否每個(gè)函數(shù)都調(diào)用了?

分支覆蓋率(branch coverage):是否每個(gè)if代碼塊都執(zhí)行了?

語句覆蓋率(statement coverage):是否每個(gè)語句都執(zhí)行了?

Istanbul?是 JavaScript 程序的代碼覆蓋率工具。

安裝

$ npm install -g istanbul

覆蓋率測(cè)試

在編寫過以上的測(cè)試用例之后,執(zhí)行命令:

istanbul cover _mocha

就能得到覆蓋率:

JerryC% istanbul cover _mocha                                                                                                                                                                


  module
    limit
      ? limit should success
    async
      ? async
    getContent
      ? getContent
    add
      ? add

  should
    #Promise
      ? should.reject
      ? should fulfilled


  6 passing (32ms)


================== Coverage summary ======================
Statements   : 100% ( 10/10 )
Branches     : 100% ( 2/2 )
Functions    : 100% ( 5/5 )
Lines        : 100% ( 10/10 )
==========================================================

這條命令同時(shí)還生成了一個(gè) coverage 子目錄,其中的 coverage.json 文件包含覆蓋率的原始數(shù)據(jù),coverage/lcov-report 是可以在瀏覽器打開的覆蓋率報(bào)告,其中有詳細(xì)信息,到底哪些代碼沒有覆蓋到。

上面命令中,istanbul cover 命令后面跟的是 _mocha 命令,前面的下劃線是不能省略的。

因?yàn)?,mocha 和 _mocha 是兩個(gè)不同的命令,前者會(huì)新建一個(gè)進(jìn)程執(zhí)行測(cè)試,而后者是在當(dāng)前進(jìn)程(即 istanbul 所在的進(jìn)程)執(zhí)行測(cè)試,只有這樣, istanbul 才會(huì)捕捉到覆蓋率數(shù)據(jù)。其他測(cè)試框架也是如此,必須在同一個(gè)進(jìn)程執(zhí)行測(cè)試。

如果要向 mocha 傳入?yún)?shù),可以寫成下面的樣子。

$ istanbul cover _mocha -- tests/test.sqrt.js -R spec

上面命令中,兩根連詞線后面的部分,都會(huì)被當(dāng)作參數(shù)傳入 Mocha 。如果不加那兩根連詞線,它們就會(huì)被當(dāng)作 istanbul 的參數(shù)(參考鏈接1,2)。

使用Makefile串起項(xiàng)目
TESTS = test/*.test.js
REPORTER = spec
TIMEOUT = 10000
JSCOVERAGE = ./node_modules/jscover/bin/jscover

test:
    @NODE_ENV=test ./node_modules/mocha/bin/mocha -R $(REPORTER) -t $(TIMEOUT) $(TESTS)

test-cov: lib-cov
    @LIB_COV=1 $(MAKE) test REPORTER=dot
    @LIB_COV=1 $(MAKE) test REPORTER=html-cov > coverage.html

lib-cov:
    @rm -rf ./lib-cov
    @$(JSCOVERAGE) lib lib-cov

.PHONY: test test-cov lib-cov

make test
make test-cov

用項(xiàng)目自身的jscover和mocha,避免版本沖突和混亂

持續(xù)集成,Travis-cli

Travis-ci

綁定Github帳號(hào)

在Github倉(cāng)庫(kù)的Admin打開Services hook

打開Travis

每次push將會(huì)hook觸發(fā)執(zhí)行npm test命令

注意:Travis會(huì)將未描述的項(xiàng)目當(dāng)作Ruby項(xiàng)目。所以需要在根目錄下加入.travis.yml文件。內(nèi)容如下:

language: node_js
node_js:
  - "0.12"

Travis-cli還會(huì)對(duì)項(xiàng)目頒發(fā)標(biāo)簽,

or?

如果項(xiàng)目通過所有測(cè)試,就會(huì)build-passing,

如果項(xiàng)目沒有通過所有測(cè)試,就會(huì)build-failing

一些觀點(diǎn)

實(shí)施單元測(cè)試的時(shí)候, 如果沒有一份經(jīng)過實(shí)踐證明的詳細(xì)規(guī)范, 很難掌握測(cè)試的 "度", 范圍太小施展不開, 太大又侵犯 "別人的" 地盤. 上帝的歸上帝, 凱撒的歸凱撒, 給單元測(cè)試念念緊箍咒不見得是件壞事, 反而更有利于發(fā)揮單元測(cè)試的威力, 為代碼重構(gòu)和提高代碼質(zhì)量提供動(dòng)力.

這份文檔來自 Geotechnical, 是一份非常難得的經(jīng)驗(yàn)準(zhǔn)則. 你完全可以以這份準(zhǔn)則作為模板, 結(jié)合所在團(tuán)隊(duì)的經(jīng)驗(yàn), 整理出一份內(nèi)部單元測(cè)試準(zhǔn)則.

單元測(cè)試準(zhǔn)則

彩蛋

最后,介紹一個(gè)庫(kù):faker

他是一個(gè)能偽造用戶數(shù)據(jù)的庫(kù),包括用戶常包含的屬性:個(gè)人信息、頭像、地址等等。

是一個(gè)開發(fā)初期,模擬用戶數(shù)據(jù)的絕佳好庫(kù)。

支持Node.js和瀏覽器端。

整理 Nodejs的單元測(cè)試工具

測(cè)試框架 mocha

斷言庫(kù):should.js、expect.js、chai

覆蓋率:istanbul、jscover、blanket

Mock庫(kù):muk

測(cè)試私有方法:rewire

Web測(cè)試:supertest

持續(xù)集成:Travis-cli

參考

https://github.com/JacksonTian/unittesting

]()[http://html5ify.com/unittesting/slides/index.html

http://www.ruanyifeng.com/blog/2015/06/istanbul.html

http://coolshell.cn/articles/8209.html

http://stackoverflow.com/questions/153234/how-deep-are-your-unit-tests

https://github.com/yangyubo/zh-unit-testing-guidelines

http://www.codedata.com.tw/java/unit-test-the-way-changes-my-programming

http://wiki.ubuntu.org.cn/%E8%B7%9F%E6%88%91%E4%B8%80%E8%B5%B7%E5%86%99Makefile:MakeFile%E4%BB%8B%E7%BB%8D

https://github.com/yangyubo/zh-unit-testing-guidelines

https://github.com/visionmedia/superagent/blob/master/Makefile

如果本文對(duì)您有用
請(qǐng)不要吝嗇你們的Follow與Start
這會(huì)大大支持我們繼續(xù)創(chuàng)作

「Github」
MZMonster :@MZMonster
JC_Huang :@JerryC8080

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

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/78938.html

相關(guān)文章

  • 深入貫徹閉包思想,全面理解JS閉包形成過程

    摘要:下面我們就羅列閉包的幾個(gè)常見問題,從回答問題的角度來理解和定義你們心中的閉包。函數(shù)可以通過作用域鏈相互關(guān)聯(lián)起來,函數(shù)內(nèi)部的變量可以保存在其他函數(shù)作用域內(nèi),這種特性在計(jì)算機(jī)科學(xué)文獻(xiàn)中稱為閉包。 寫這篇文章之前,我對(duì)閉包的概念及原理模糊不清,一直以來都是以通俗的外層函數(shù)包裹內(nèi)層....來欺騙自己。并沒有說這種說法的對(duì)與錯(cuò),我只是不想擁有從眾心理或者也可以說如果我們說出更好更低層的東西,逼格...

    snowell 評(píng)論0 收藏0
  • 測(cè)試你的前端代碼 - part2(單元測(cè)試

    摘要:?jiǎn)卧獪y(cè)試上一節(jié)有討論過,單元測(cè)試就是以代碼單元為單位進(jìn)行測(cè)試,代碼單元可以是一個(gè)函數(shù),一個(gè)模塊,或者一個(gè)類。單元測(cè)試是最容易理解也最容易實(shí)現(xiàn)的測(cè)試方式。在寫單元測(cè)試的時(shí)候,盡量將你的單元測(cè)試獨(dú)立出來,不要幾個(gè)單元互相引用。 showImg(https://segmentfault.com/img/remote/1460000008823416?w=997&h=350); 本文作者:G...

    daydream 評(píng)論0 收藏0
  • 測(cè)試你的前端代碼 - part2(單元測(cè)試

    摘要:?jiǎn)卧獪y(cè)試上一節(jié)有討論過,單元測(cè)試就是以代碼單元為單位進(jìn)行測(cè)試,代碼單元可以是一個(gè)函數(shù),一個(gè)模塊,或者一個(gè)類。單元測(cè)試是最容易理解也最容易實(shí)現(xiàn)的測(cè)試方式。在寫單元測(cè)試的時(shí)候,盡量將你的單元測(cè)試獨(dú)立出來,不要幾個(gè)單元互相引用。 showImg(https://segmentfault.com/img/remote/1460000008823416?w=997&h=350); 本文作者:G...

    shadajin 評(píng)論0 收藏0
  • 消息系統(tǒng)設(shè)計(jì)與實(shí)現(xiàn)「上篇」

    摘要:原文鏈接消息系統(tǒng)設(shè)計(jì)與實(shí)現(xiàn)上篇由于文章篇幅較長(zhǎng),而作者精力有限,不希望這么早就精盡人亡,故分成上下篇來寫消息系統(tǒng)的設(shè)計(jì)與實(shí)現(xiàn)。更新于關(guān)聯(lián)文章消息系統(tǒng)設(shè)計(jì)與實(shí)現(xiàn)下篇如果本文對(duì)您有用請(qǐng)不要吝嗇你們的與這會(huì)大大支持我們繼續(xù)創(chuàng)作 原文鏈接:Bluesun | 消息系統(tǒng)設(shè)計(jì)與實(shí)現(xiàn)「上篇」 由于文章篇幅較長(zhǎng),而作者精力有限,不希望這么早就精盡人亡,故分成上下篇來寫消息系統(tǒng)的設(shè)計(jì)與實(shí)現(xiàn)。上篇主要講...

    v1 評(píng)論0 收藏0
  • 關(guān)于前端開發(fā)談?wù)?em>單元測(cè)試

    摘要:很快我發(fā)現(xiàn)有一個(gè)誤區(qū),許多人認(rèn)為單元測(cè)試必須是一個(gè)集中運(yùn)行所有單元的測(cè)試,并一目了然。許多人認(rèn)為單元測(cè)試,甚至整個(gè)測(cè)試都是在編碼結(jié)束后的一道工序,而修復(fù)也不過是在做垃圾掩埋一類的工作。 單元測(cè)試Unit Test 很早就知道單元測(cè)試這樣一個(gè)概念,但直到幾個(gè)月前,我真正開始接觸和使用它。究竟什么是單元測(cè)試?我想也許很多使用了很久的人也不一定能描述的十分清楚,所以寫了這篇文章來嘗試描述它...

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

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

0條評(píng)論

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