Node入門教程(13)第十一章:mocha單元測試+should斷言庫+istanbul覆蓋率測試+art-template

聲明:
如下爲老馬的全棧視頻教程的筆記,若是須要了解詳情,請直接配合視頻學習。視頻所有免費,視頻地址:https://ke.qq.com/course/294595?tuin=1eb4a0a4javascript

nodemon 來進行自動重啓 app 應用

$ npm i -g nodemon  # 使用: nodemon app.js 

art-template 模板使用

官網: https://aui.github.io/art-template/zh-cn/index.htmlphp

第一步: 引入 art-template 的包css

npm install --save art-template
npm install --save express-art-template

第二步:項目中設置 express 的應用 art-template 模板引擎html

const art_express = require('express-art-template'); const app = express(); // 建立app對象。 // 設置art的模板引擎 app.engine('art', art_express); app.get('/user/list', (req, res) => { res.render('users/userlist2.art', { title: '你好啊!', users: userService.getUsers() }); }); 

語法

  • 輸出標準語法
{{value}}
{{data.key}}
{{data['key']}} {{a ? b : c}} {{a || b}} {{a + b}} 
  • 原始語法
<%= value %> <%= data.key %> <%= data['key'] %> <%= a ? b : c %> <%= a || b %> <%= a + b %> 

模板一級特殊變量能夠使用 $data 加下標的方式訪問:java

{{$data['user list']}}node

  • 原文輸出標準語法

{{@ value }}
原始語法git

<%- value %>github

原文輸出語句不會對 HTML 內容進行轉義處理,可能存在安全風險,請謹慎使用。shell

  • 條件標準語法
{{if value}} ... {{/if}} {{if v1}} ... {{else if v2}} ... {{/if}} 

原始語法express

<% if (value) { %> ... <% } %> <% if (v1) { %> ... <% } else if (v2) { %> ... <% } %> 
  • 循環標準語法
{{each target}}
{{$index}} {{$value}} {{/each}} 

原始語法

<% for(var i = 0; i < target.length; i++){ %> <%= i %> <%= target[i] %> <% } %> 

target 支持 array 與 object 的迭代,其默認值爲 $data。
$value 與 $index 能夠自定義:{{each target val key}}。變量標準語法

{{set temp = data.sub.content}}
原始語法

<% var temp = data.sub.content; %>

  • 模板繼承標準語法
{{extend './layout.art'}} {{block 'head'}} ... {{/block}} 

原始語法

<% extend('./layout.art') %> <% block('head', function(){ %> ... <% }) %> 

模板繼承容許你構建一個包含你站點共同元素的基本模板「骨架」。範例:

<!--layout.art--> <!doctype html> <html> <head> <meta charset="utf-8"> <title>{{block 'title'}}My Site{{/block}}</title> {{block 'head'}} <link rel="stylesheet" href="main.css"> {{/block}} </head> <body> {{block 'content'}}{{/block}} </body> </html> <!--index.art--> {{extend './layout.art'}} {{block 'title'}}{{title}}{{/block}} {{block 'head'}} <link rel="stylesheet" href="custom.css"> {{/block}} {{block 'content'}} <p>This is just an awesome page.</p> {{/block}} 

渲染 index.art 後,將自動應用佈局骨架。

  • 子模板標準語法
{{include './header.art'}} {{include './header.art' data}} 

原始語法

<% include('./header.art') %> <% include('./header.art', data) %> 

data 數默認值爲 $data;標準語法不支持聲明 object 與 array,只支持引用變量,而原始語法不受限制。
art-template 內建 HTML 壓縮器,請避免書寫 HTML 非正常閉合的子模板,不然開啓壓縮後標籤可能會被意外「優化。過濾器註冊過濾器

template.defaults.imports.dateFormat = function(date, format){/_[code..]_/};
template.defaults.imports.timestamp = function(value){return value \* 1000};

  • 過濾器函數第一個參數接受目標值。

標準語法

{{date | timestamp | dateFormat 'yyyy-MM-dd hh:mm:ss'}} {{value | filter}} 過濾器語法相似管道操做符,它的上一個輸出做爲下一個輸入。 

原始語法

<%= $imports.dateFormat($imports.timestamp(date), 'yyyy-MM-dd hh:mm:ss') %> 

使用 mock.js 模擬數據

官網地址: http://mockjs.com/

安裝:
npm install mockjs

// 使用 Mock var Mock = require('mockjs'); let data = Mock.mock({ "users|33": [{ "id|+1": 20000, "name": "@cname", "email": "@email", "phone": "@natural(132000000,133000000)", "address": "@county(true)", "zip": "@zip", "birthday": "@date('yyyy-MM-dd')" }] }); // 輸出結果 console.log(JSON.stringify(data, null, 4)); 

mocha 幫助咱們進行單元測試

安裝

$ npm install --global mocha 

建立測試文件夾 test 目錄,而後添加測試腳本文件

// 引用node的默認的斷言庫 var assert = require('assert'); // 建立描述場景 describe('Array', function() { // 場景能夠進行嵌套 describe('#indexOf()', function() { // 實際的測試用例 it('should return -1 when the value is not present', function() { assert.equal(-1, [1, 2, 3].indexOf(4)); }); }); }); 

執行測試:

$ mocha 

BDD 的 api

行爲驅動開發(英語:Behavior-driven development,縮寫 BDD)是一種敏捷軟件開發的技術,它鼓勵軟件項目中的開發者、QA 和非技術人員或商業參與者之間的協做。BDD(行爲驅動開發 )是第二代的、由外及內的、基於拉(pull)的、多方利益相關者的(stakeholder)、多種可擴展的、高自動化的敏捷方法。它描述了一個交互循環,能夠具備帶有良好定義的輸出(即工做中交付的結果):已測試過的軟件。

mocha 默認的測試接口是 bdd 的方式。

  • describe():描述場景,在裏面能夠設定 Context,可包括多個測試用例,也能夠嵌套場景
  • it():位於場景內,描述測試用例
  • before():全部測試用例的統一前置動做
  • after():全部測試用例的統一後置動做
  • beforeEach():每一個測試用例的前置動做
  • afterEach():每一個測試用例的後置動做
describe('Array', function() { before(function() { // ... }); describe('#indexOf()', function() { it('should return -1 when not present', function() { [1, 2, 3].indexOf(4).should.equal(-1); }); }); after(function() { // ... }); }); 

TDD 的 api

TDD,全稱 Test-driven Development,中文測試驅動開發,主要方法:先寫測試用例(test case),測試用例寫好後,再來實現須要實現的方法或功能。

如下是 TDD 的接口列表

  • suite:定義一組測試用例。

  • suiteSetup:此方法會在這個 suite 全部測試用例執行前執行一次,只一次,這是跟 setup 的區別。

  • setup:此方法會在每一個測試用例執行前都執行一遍。

  • test:具體執行的測試用例實現代碼。

  • teardown:此方法會在每一個測試用例執行後都執行一遍,與 setup 相反。

  • suiteTeardown:此方法會在這個 suite 全部測試用例執行後執行一次,與 suiteSetup 相反。

這些接口都是與 TDD 概念中的接口對應與相關實現,方便組織測試用例。BDD 的接口在這裏不予贅述,可參考官方文檔。

var assert = require('assert'); var mocha = require('mocha'); var suite = mocha.suite; var setup = mocha.setup; var suiteSetup = mocha.suiteSetup; var test = mocha.test; var teardown = mocha.teardown; var suiteTeardown = mocha.suiteTeardown; //test case suite('Array', function() { suiteSetup(function() { //suiteSetup will run only 1 time in suite Array, before all suite //... console.log('suitSetup...'); }); setup(function() { //setup will run 1 time before every suite runs in suite Array //... console.log('setup...'); }); suite('indexOf()', function() { test('should return -1 when not present', function() { assert.equal(-1, [1, 2, 3].indexOf(4)); }); }); suite('indexOf2()', function() { test('should return not -1 when present', function() { assert.equal(0, [1, 2, 3].indexOf(1)); }); }); teardown(function() { //teardown will run 1 time after every suite runs in suite Array //... console.log('teardown...'); }); suiteTeardown(function() { //suiteTeardown will run 1 time in suite Array, after all suits run over. //... console.log('suiteTeardown...'); }); }); 

should.js 斷言庫的用法

安裝

$ npm install should -P 

構建斷言對象

should 提供了一個全局方法,構造一個斷言對象。

const should = require('should'); var obj = { a: 123 }; should(obj).eqls({ a: 123 }); should(obj).be.a.Object(); 

另外 should 劫持了 Object 的原型對象,因此全部的對象都擁有了 should 方法。should.js 源碼以下:

/** * Expose api via `Object#should`. * * @api public */ Object.defineProperty(Object.prototype, 'should', { set: function() {}, get: function() { return should(this); }, configurable: true }); 

因此代碼中能夠直接用 should 方法構建斷言對象。

const a = { b: 123 }; a.should.be.a.Object(); a.b.should.above(3); 

經常使用的 api

  • eql(別名:eqls) 相等,不嚴格相等。對象比較屬性值,而非地址: should(3).eql(3)
  • notEqual : should(3).notEqual(45)
  • equal (同 Nodejs 的 assert.equal 方法): should(3).equal(3)
  • should.ok(value, [message])
  • true([message]): should(3>1).true()
  • containEql(other) [1, 2, 3].should.containEql(1);
  • above() :(10).should.be.above(0);
  • belowOrEqual(n, [description]): (0).should.be.belowOrEqual(10);
  • NaN: (10).should.not.be.NaN();
  • length: [1, 2].should.have.length(2);

其餘

'abca'.should.endWith('a'); 'abc'.should.startWith('a'); ({ a: 10 }.should.have.value('a', 10)); ({ a: 10 }.should.have.property('a')); 'ab'.should.be.equalOneOf('a', 10, 'ab'); 

鏈式調用

should 實現了能夠直接鏈式編程的效果,這些方法內部都是返回斷言對象自身,可是語義化卻厲害了,其中能夠直接應用鏈式編程的有:['an', 'of', 'a', 'and', 'be', 'has', 'have', 'with', 'is', 'which', 'the', 'it']

應用:

const should = require('should'); describe('#getUsers 測試獲取用戶全部數據', function() { it('service.getUsers() should be Array', function() { should(service.getUsers()).be.a.Array(); }); it('service.getPageUsers(2, 5) should return Array[]', function() { let data = service.getPageUsers(2, 5); // should(users).be.a.Object(); (data.users.length <= 5).should.be.true(); let returnUser = service.addUser(addUser); returnUser.should.containEql(addUser); returnMsg.should.be.eql({ status: 1, msg: '刪除成功' }); service.getUserById(10008).should.be.containEql({ status: 1, msg: 'ok' }); }); }); 

istanbul 測試覆蓋率

代碼覆蓋率(code coverage)。它有四個測量維度。

  • 行覆蓋率(line coverage):是否每一行都執行了?
  • 函數覆蓋率(function coverage):是否每一個函數都調用了?
  • 分支覆蓋率(branch coverage):是否每一個 if 代碼塊都執行了?
  • 語句覆蓋率(statement coverage):是否每一個語句都執行了?

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

安裝

$ npm install -g istanbul 

覆蓋率測試 demo

$ istanbul cover simple.js ===== Coverage summary ===== Statements : 75% ( 3/4 ) Branches : 50% ( 1/2 ) Functions : 100% ( 0/0 ) Lines : 75% ( 3/4 ) ============================= 

這條命令同時還生成了一個 coverage 子目錄,其中的 coverage.json 文件包含覆蓋率的原始數據,coverage/lcov-report 是能夠在瀏覽器打開的覆蓋率報告,其中有詳細信息,到底哪些代碼沒有覆蓋到。

配合 mocha 測試覆蓋率統計

$ istanbul cover _mocha 

上面命令中,istanbul cover 命令後面跟的是 _mocha 命令,前面的下劃線是不能省略的。由於,mocha 和 _mocha 是兩個不一樣的命令,前者會新建一個進程執行測試,然後者是在當前進程(即 istanbul 所在的進程)執行測試,只有這樣, istanbul 纔會捕捉到覆蓋率數據。其餘測試框架也是如此,必須在同一個進程執行測試。

若是要向 mocha 傳入參數,能夠寫成下面的樣子。

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

上面命令中,兩根連詞線後面的部分,都會被看成參數傳入 Mocha 。若是不加那兩根連詞線,它們就會被看成 istanbul 的參數


老馬免費視頻教程

返回教程列表首頁

github地址:https://github.com/malun666/aicoder_node

相關文章
相關標籤/搜索