Nodejs開源項目裏怎麼樣寫測試、CI和代碼測試覆蓋率

wx 是一個不錯的微信應用框架,接口和網站作的也不錯,和wechat-api是相似的項目javascript

羣裏有人問哪一個好html

樸靈說:「不寫測試的項目都不是好項目」java

確實wx目前尚未測試,對於一個開源項目來講,沒有測試和代碼覆蓋率是不完善的,並且從技術選型來講,大可能是不敢選的。node

那麼Nodejs開源項目裏怎麼樣寫測試、CI和代碼測試覆蓋率呢?jquery

測試

目前主流的就bdd和tdd,本身查一下差別git

推薦程序員

  • mocha和tape

另外Jasmine也挺有名,angularjs用它,不過挺麻煩的,還有一個選擇是qunit,最初是爲jquery測試寫的,在nodejs裏用仍是以爲怪怪的。angularjs

若是想簡單能夠tap,它和tape很像,下文會有詳細說明github

mocha

mocha是tj寫的web

https://github.com/mochajs/mocha

var assert = require("assert")
describe('truth', function(){
  it('should find the truth', function(){
    assert.equal(1, 1);
  })
})

斷言風格,這裏默認是assert,推薦使用chaijs這個模塊,它提供3種風格

  • Should
  • Expect
  • Assert

rspec裏推薦用expect,其實看我的習慣

比較典型一個mocha例子

var assert = require('chai').assert;
var expect = require('chai').expect;
require('chai').should();


describe('Test', function(){
	before(function() {
    // runs before all tests in this block
	
  })
  after(function(){
    // runs after all tests in this block
  })
  beforeEach(function(){
    // runs before each test in this block
  })
  afterEach(function(){
    // runs after each test in this block
  })

  describe('#test()', function(){
    it('should return ok when test finished', function(done){
      assert.equal('sang_test2', 'sang_test2');
      var foo = 'bar';
      expect(foo).to.equal('bar');
      done()
    })
  })
})

說明

  • 理解測試生命週期
  • 理解bdd測試寫法

單元測試須要的各個模塊說明

  • mocha(Mocha is a feature-rich JavaScript test framework running on node.js and the browser, making asynchronous testing simple and fun.)
  • chai(Chai is a BDD / TDD assertion library for node and the browser that can be delightfully paired with any javascript testing framework.)
  • sinon(Standalone test spies, stubs and mocks for JavaScript.)
  • zombie (頁面事件模擬Zombie.js is a lightweight framework for testing client-side JavaScript code in a simulated environment. No browser required.)
  • supertest(接口測試 Super-agent driven library for testing node.js HTTP servers using a fluent API)

更多的看 http://nodeonly.com/2014/11/24/mongoose-test.html

若是你想真正的玩敏捷,從用戶故事開始,那麼下面這2個庫很是必要

啊,黃瓜。。。。

tape:像代碼同樣跑測試

tape是substack寫的測試框架

https://github.com/substack/tape

var test = require('tape').test;
test('equivalence', function(t) {
    t.equal(1, 1, 'these two numbers are equal');
    t.end();
});

tape是很是簡單的測試框架,核心價值觀是」Tests are code」,因此你能夠像代碼同樣跑測試,

好比

node test/test.js

寫個腳本就無比簡單了。固然若是你想加'test runner' 庫也有現成的。

The Test Anything Protocol

TAP全稱是Test Anything Protocol

它是可靠性測試的一種(tried & true)實現

從1987就有了,有不少語言都實現了。

它說白點就是用賊簡單的方式來格式化測試結果,好比

TAP version 13
# equivalence
ok 1 these two numbers are equal

1..1
# tests 1
# pass  1

# ok

好比node裏的實現https://github.com/isaacs/node-tap

var tap = require('tap')

// you can test stuff just using the top level object.
// no suites or subtests required.

tap.equal(1, 1, 'check if numbers still work')
tap.notEqual(1, 2, '1 should not equal 2')

// also you can group things into sub-tests.
// Sub-tests will be run in sequential order always,
// so they're great for async things.

tap.test('first stuff', function (t) {
  t.ok(true, 'true is ok')
  t.similar({a: [1,2,3]}, {a: [1,2,3]})
  // call t.end() when you're done
  t.end()
})

必定要區分tap和tape,不要弄混了

科普一下什麼是CI

科普一下,CI = Continuous integration 持續集成

Martin Fowler對持續集成是這樣定義的:

持續集成是一種軟件開發實踐,即團隊開發成員常常集成他們的工做,一般每一個成員天天至少集成一次,也就意味着天天可能會發生屢次集成。每次集成都經過自動化的構建(包括編譯,發佈,自動化測試)來驗證,從而儘快地發現集成錯誤。許多團隊發現這個過程能夠大大減小集成的問題,讓團隊可以更快的開發內聚的軟件。

它能夠

  • 減小風險
  • 減小重複過程
  • 任什麼時候間、任何地點生成可部署的軟件
  • 加強項目的可見性
  • 創建團隊對開發產品的信心

要素

1.統一的代碼庫 2.自動構建 3.自動測試 4.每一個人天天都要向代碼庫主幹提交代碼 5.每次代碼遞交後都會在持續集成服務器上觸發一次構建 6.保證快速構建 7.模擬生產環境的自動測試 8.每一個人均可以很容易的獲取最新可執行的應用程序 9.每一個人都清楚正在發生的情況 10.自動化的部署

也就是說,測試不經過不能部署,只有提交到服務器上,就能夠自動跑測試,測試經過後,就能夠部署到服務器上了(注意是"staging", 而非"production")。

通常最常的ci軟件是jenkins

舉個你們熟悉的例子iojs開發中的持續集成就是用的jenkins

https://jenkins-iojs.nodesource.com/

4.png

jenkins是自建環境下用的比較多,若是是開源項目,推薦travis-ci

https://travis-ci.org/

對開源項目作持續集成是免費的(非開源的好貴),因此在github集成的基本是最多的。

對nodejs支持的也很是好。

舉2個例子

測試報告

近年隨着tdd/bdd,開源項目,和敏捷開發的火熱,程序員們再也不知足說,我貢獻了一個開源項目

要有高要求,我要加測試

要有更高要求,我要把每個函數都測試到,讓別人相信個人代碼沒有任何問題

上一小節講的ci,實際上解決了反覆測試的自動化問題。可是如何看個人程序裏的每個函數都測試了呢?

答案是測試覆蓋率

在nodejs裏,推薦istanbul

Istanbul - 官方介紹 a JS code coverage tool written in JS

它能夠經過3種途徑生成覆蓋報告

  • cli
  • 代碼
  • gulp插件

安裝

$ npm install -g istanbul

執行

$ istanbul cover my-test-script.js -- my test args

它會生成./coverage目錄,這裏面就是測試報告

好比個人項目裏

./node_modules/.bin/istanbul cover ./node_modules/mocha/bin/_mocha --report lcovonly
    #MongooseDao()
      ✓ should return ok when record create
      ✓ should return ok when record delete fixture-user
      ✓ should return ok when record deleteById
      ✓ should return ok when record removeById
      ✓ should return ok when record getById
      ✓ should return ok when record getAll
      ✓ should return ok when record all
      ✓ should return ok when record query


  8 passing (50ms)

=============================================================================
Writing coverage object [/Users/sang/workspace/moa/mongoosedao/coverage/coverage.json]
Writing coverage reports at [/Users/sang/workspace/moa/mongoosedao/coverage]
=============================================================================

=============================== Coverage summary ===============================
Statements   : 47.27% ( 26/55 )
Branches     : 8.33% ( 1/12 )
Functions    : 60% ( 9/15 )
Lines        : 47.27% ( 26/55 )
================================================================================

默認,它會生成coverage.json和Icov.info,若是你想生成html也能夠的。

好比說,上面的結果47.27%是我測試覆蓋的佔比,即55個函數,個人測試裏只覆蓋了26個。

那麼我須要有地方可以展現出來啊

實踐

咱們以mongoosedao項目爲例,介紹一下如何集成測試,ci和測試覆蓋率

最終效果如圖 5.png

npm run

package.json裏定義自定義執行腳本

"scripts": {
  "start": "npm publish .",
  "test": "./node_modules/.bin/gulp",
  "mocha": "./node_modules/.bin/mocha -u bdd",
  "cov":"./node_modules/.bin/istanbul cover ./node_modules/mocha/bin/_mocha --report lcovonly -- -R spec && cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js && rm -rf ./coverage"
},

除了start和test外,都是自定義任務,其餘都要加run命令

npm run mocha
npm run cov

更多見npm-run-test教程

gulp watch

var gulp = require('gulp');
var watch = require('gulp-watch');

var path = 'test/**/*.js';

gulp.task('watch', function() {
  gulp.watch(['test/**/*.js', 'lib/*.js'], ['mocha']);
});

var mocha = require('gulp-mocha');

gulp.task('mocha', function () {
    return gulp.src(path , {read: false})
        // gulp-mocha needs filepaths so you can't have any plugins before it 
        .pipe(mocha({reporter: 'spec'}));
});


gulp.task('default',['mocha', 'watch']);

這樣就能夠執行gulp的時候,當文件變更,會自動觸發mocha測試,簡化每次都輸入npm test這樣的操做。

固然你能夠玩更多的gulp,若是不熟悉,參考

建立.travis.yml

項目根目錄下,和package.json平級

language: node_js
repo_token: COVERALLS.IO_TOKEN
services: mongodb
node_js:
  - "0.12"
  - "0.11"
  - "0.10"
script: npm run mocha
after_script:
  npm run cov

說明

  • 若是依賴mongo等數據庫,必定要寫services
  • 把測試覆蓋率放到執行測試以後,避免報402錯誤

在travis-ci.org上,github受權,添加repo都比較簡單

添加以後,就能夠看到,好比

https://travis-ci.org/moajs/mongoosedao

travis-ci實際上根據github的代碼變更進行自動持續構建,可是有的時候它不必定更新,或者說,你須要手動選一下:

1.png

點擊# 10 passed,這樣就能夠強制它手動集成了。

其餘都很簡單,注意替換COVERALLS.IO_TOKEN便可。

建立 .coveralls.yml

https://coveralls.io/是一個代碼測試覆蓋率的網站,

nodejs下面的代碼測試覆蓋率,原理是經過istanbul生成測試數據,上傳到coveralls網站上,而後以badge的形式展現出來

好比

Coverage Status

具體實踐和travis-ci相似,用github帳號登錄,而後添加repo,而後在項目根目錄下,和package.json平級,增長.coveralls.yml

service_name: travis-pro
repo_token: 99UNur6O7ksBqiwgg1NG1sSFhmu78A0t7

在上,第一次添加repo,顯示的是「SET UP COVERALLS」,裏面有token,須要放到.coveralls.yml裏,

2.png

若是成功提交了,就能夠看到數據了

3.png

在readme.md裏增長badge

[![Build Status](https://travis-ci.org/moajs/mongoosedao.png?branch=master)](https://travis-ci.org/moajs/mongoosedao)
[![Coverage Status](https://coveralls.io/repos/moajs/mongoosedao/badge.png)](https://coveralls.io/r/moajs/mongoosedao)

它就會顯示以下

Build Status Coverage Status

另一種用Makefile的玩法實踐

舉例:https://github.com/node-webot/wechat-api/blob/master/Makefile

TESTS = test/*.js
REPORTER = spec
TIMEOUT = 20000
ISTANBUL = ./node_modules/.bin/istanbul
MOCHA = ./node_modules/mocha/bin/_mocha
COVERALLS = ./node_modules/coveralls/bin/coveralls.js

test:
	@NODE_ENV=test $(MOCHA) -R $(REPORTER) -t $(TIMEOUT) \
		$(MOCHA_OPTS) \
		$(TESTS)

test-cov:
	@$(ISTANBUL) cover --report html $(MOCHA) -- -t $(TIMEOUT) -R spec $(TESTS)

test-coveralls:
	@$(ISTANBUL) cover --report lcovonly $(MOCHA) -- -t $(TIMEOUT) -R spec $(TESTS)
	@echo TRAVIS_JOB_ID $(TRAVIS_JOB_ID)
	@cat ./coverage/lcov.info | $(COVERALLS) && rm -rf ./coverage

test-all: test test-coveralls

.PHONY: test

我我的更喜歡npm+gulp的寫法,老是有一種make是c裏古老的東東。。。

總結

本文講了

  • nodejs裏經常使用框架
    • mocha
    • tape
    • tap
    • 前沿技術:cucumber和vowsjs
  • 科普一下CI
  • 測試報告
    • istanbul
  • 實踐
    • gulp + npm run
    • mocha
    • travis-ci
    • coveralls
  • 介紹了基於makefile的另外一種玩法

全文完

歡迎關注個人公衆號【node全棧】

node全棧.png

相關文章
相關標籤/搜索