日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問(wèn)題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷解決方案
通過(guò)構(gòu)建自己的JavaScript測(cè)試框架來(lái)了解JS測(cè)試

測(cè)試(單元或集成)是編程中非常重要的一部分。在當(dāng)今的軟件開(kāi)發(fā)中,單元/功能測(cè)試已成為軟件開(kāi)發(fā)的組成部分。隨著Nodejs的出現(xiàn),我們已經(jīng)看到了許多超級(jí)JS測(cè)試框架的發(fā)布:Jasmine,Jest等。

成都創(chuàng)新互聯(lián)公司主營(yíng)望謨網(wǎng)站建設(shè)的網(wǎng)絡(luò)公司,主營(yíng)網(wǎng)站建設(shè)方案,成都app軟件開(kāi)發(fā),望謨h5小程序開(kāi)發(fā)搭建,望謨網(wǎng)站營(yíng)銷推廣歡迎望謨等地區(qū)企業(yè)咨詢

單元測(cè)試框架

這有時(shí)也稱為隔離測(cè)試,它是測(cè)試獨(dú)立的小段代碼的實(shí)踐。如果你的測(cè)試使用某些外部資源(例如網(wǎng)絡(luò)或數(shù)據(jù)庫(kù)),則不是單元測(cè)試。

單元測(cè)試框架試圖以人類可讀的格式描述測(cè)試,以便非技術(shù)人員可以理解所測(cè)試的內(nèi)容。然而,即使你是技術(shù)人員,BDD格式的閱讀測(cè)試也會(huì)使你更容易理解所發(fā)生的事情。

例如,如果我們要測(cè)試此功能:

 
 
 
 
  1. function helloWorld() { 
  2.   return 'Hello world!'; 

我們會(huì)像這樣寫(xiě)一個(gè)jasmine測(cè)試規(guī)范:

 
 
 
 
  1. describe('Hello world', () => { ① 
  2.   it('says hello', () => { ② 
  3.       expect(helloWorld())③.toEqual('Hello world!'); ④ 
  4.   }); 
  5. }); 

說(shuō)明:

 
 
 
 
  1. describe(string, function) 
  2. it(string, function) 

安裝和拆卸

有時(shí)候?yàn)榱藴y(cè)試一個(gè)功能,我們需要進(jìn)行一些設(shè)置,也許是創(chuàng)建一些測(cè)試對(duì)象。另外,完成測(cè)試后,我們可能需要執(zhí)行一些清理活動(dòng),也許我們需要從硬盤(pán)驅(qū)動(dòng)器中刪除一些文件。

這些活動(dòng)稱為“設(shè)置和拆卸”(用于清理),Jasmine有一些功能可用來(lái)簡(jiǎn)化此工作:

  • beforeAll 這個(gè)函數(shù)在describe測(cè)試套件中的所有規(guī)范運(yùn)行之前被調(diào)用一次。
  • afterAll 在測(cè)試套件中的所有規(guī)范完成后,該函數(shù)將被調(diào)用一次。
  • beforeEach 這個(gè)函數(shù)在每個(gè)測(cè)試規(guī)范之前被調(diào)用, it 函數(shù)已經(jīng)運(yùn)行。
  • afterEach 在運(yùn)行每個(gè)測(cè)試規(guī)范之后調(diào)用此函數(shù)。

在Node中的使用

在Node項(xiàng)目中,我們?cè)谂c src 文件夾相同目錄的 test 文件夾中定義單元測(cè)試文件:

 
 
 
 
  1. node_prj 
  2.     src/ 
  3.         one.js 
  4.         two.js 
  5.     test/ 
  6.         one.spec.js 
  7.         two.spec.js 
  8.     package.json 

該測(cè)試包含規(guī)格文件,這些規(guī)格文件是src文件夾中文件的單元測(cè)試, package.json 在 script 部分進(jìn)行了 test 。

 
 
 
 
  1.   ..., 
  2.   "script": { 
  3.       "test": "jest" // or "jasmine" 
  4.     } 

如果 npm run test 在命令行上運(yùn)行,則jest測(cè)試框架將運(yùn)行 test 文件夾中的所有規(guī)范文件,并在命令行上顯示結(jié)果。

現(xiàn)在,我們知道了期望和構(gòu)建的內(nèi)容,我們繼續(xù)創(chuàng)建自己的測(cè)試框架。我們的這個(gè)框架將基于Node,也就是說(shuō),它將在Node上運(yùn)行測(cè)試,稍后將添加對(duì)瀏覽器的支持。

我們的測(cè)試框架將包含一個(gè)CLI部分,該部分將從命令行運(yùn)行。第二部分將是測(cè)試框架的源代碼,它將位于lib文件夾中,這是框架的核心。

首先,我們首先創(chuàng)建一個(gè)Node項(xiàng)目。

 
 
 
 
  1. mkdir kwuo 
  2. cd kwuo 
  3. npm init -y 

安裝chalk依賴項(xiàng),我們將需要它來(lái)為測(cè)試結(jié)果上色: npm i chalk 。

創(chuàng)建一個(gè)lib文件夾,其中將存放我們的文件。

 
 
 
 
  1. mkdir lib 

我們創(chuàng)建一個(gè)bin文件夾是因?yàn)槲覀兊目蚣軐⒂米鱊ode CLI工具。

 
 
 
 
  1. mkdir bin 

首先創(chuàng)建CLI文件。

在bin文件夾中創(chuàng)建kwuo文件,并添加以下內(nèi)容:

 
 
 
 
  1. #!/usr/bin/env node 
  2.  
  3. process.title = 'kwuo' 
  4. require('../lib/cli/cli') 

我們將hashbang設(shè)置為指向 /usr/bin/env node,這樣就可以在不使用node命令的情況下運(yùn)行該文件。

我們將process的標(biāo)題設(shè)置為“kwuo”,并要求文件“l(fā)ib/cli/cli”,這樣就會(huì)調(diào)用文件cli.js,從而啟動(dòng)整個(gè)測(cè)試過(guò)程。

現(xiàn)在,我們創(chuàng)建“l(fā)ib/cli/cli.js”并填充它。

 
 
 
 
  1. mkdir lib/cli 
  2. touch lib/cli/cli.js 

該文件將搜索測(cè)試文件夾,在“test”文件夾中獲取所有測(cè)試文件,然后運(yùn)行測(cè)試文件。

在實(shí)現(xiàn)“l(fā)ib/cli/cli.js”之前,我們需要設(shè)置全局變量。

測(cè)試文件中使用了describe,beforeEach,beforeEach,afterAll,beforeAll函數(shù):

 
 
 
 
  1. describe('Hello world', () => {  
  2.   it('says hello', () => {  
  3.     expect(helloWorld()).toEqual('Hello world!'); 
  4.   }); 
  5. }); 

但是在測(cè)試文件中都沒(méi)有定義。沒(méi)有ReferenceError的情況下文件和函數(shù)如何運(yùn)行?因?yàn)闇y(cè)試框架在運(yùn)行測(cè)試文件之前,會(huì)先實(shí)現(xiàn)這些函數(shù),并將其設(shè)置為globals,所以測(cè)試文件調(diào)用測(cè)試框架已經(jīng)設(shè)置好的函數(shù)不會(huì)出錯(cuò)。而且,這使測(cè)試框架能夠收集測(cè)試結(jié)果并顯示失敗或通過(guò)的結(jié)果。

讓我們?cè)趌ib文件夾中創(chuàng)建一個(gè) index.js 文件:

 
 
 
 
  1. touch lib/index.js 

在這里,我們將設(shè)置全局變量并實(shí)現(xiàn) describe , it , expectEach , beforeEach , afterAll , beforeAll 函數(shù)。

 
 
 
 
  1. // lib/index.js 
  2.  
  3. const chalk = require('chalk') 
  4. const log = console.log 
  5. var beforeEachs = [] 
  6. var afterEachs = [] 
  7. var afterAlls = [] 
  8. var beforeAlls = [] 
  9. var Totaltests = 0 
  10. var passedTests = 0 
  11. var failedTests = 0 
  12. var stats = [] 
  13. var currDesc = { 
  14.   it: [] 
  15.  
  16. var currIt = {} 
  17.  
  18. function beforeEach(fn) { 
  19.   beforeEachs.push(fn) 
  20.  
  21. function afterEach(fn) { 
  22.   afterEachs.push(fn) 
  23.  
  24. function beforeAll(fn) { 
  25.   beforeAlls.push(fn) 
  26.  
  27. function afterAll(fn) { 
  28.   afterAlls.push(fn) 
  29.  
  30. function expect(value) { 
  31.   return { 
  32.  
  33.     // Match or Asserts that expected and actual objects are same. 
  34.     toBe: function(expected) { 
  35.       if (value === expected) { 
  36.         currIt.expects.push({ name: `expect ${value} toBe ${expected}`, status: true }) 
  37.         passedTests++ 
  38.       } else { 
  39.         currIt.expects.push({ name: `expect ${value} toBe ${expected}`, status: false }) 
  40.         failedTests++ 
  41.       } 
  42.     }, 
  43.  
  44.     // Match the expected and actual result of the test. 
  45.     toEqual: function(expected) { 
  46.       if (value == expected) { 
  47.         currIt.expects.push({ name: `expect ${value} toEqual ${expected}`, status: true }) 
  48.         passedTests++ 
  49.       } else { 
  50.         currIt.expects.push({ name: `expect ${value} toEqual ${expected}`, status: false }) 
  51.         failedTests++ 
  52.       } 
  53.     } 
  54.   } 
  55.  
  56. function it(desc, fn) { 
  57.   Totaltests++ 
  58.   if (beforeEachs) { 
  59.     for (var index = 0; index < beforeEachs.length; index++) { 
  60.       beforeEachs[index].apply(this) 
  61.     } 
  62.   } 
  63.   //var f = stats[stats.length - 1] 
  64.   currIt = { 
  65.     name: desc, 
  66.     expects: [] 
  67.   } 
  68.   //f.push(desc) 
  69.   fn.apply(this) 
  70.   for (var index = 0; index < afterEachs.length; index++) { 
  71.     afterEachs[index].apply(this) 
  72.   } 
  73.   currDesc.it.push(currIt) 
  74.  
  75. function describe(desc, fn) { 
  76.   currDesc = { 
  77.     it: [] 
  78.   } 
  79.   for (var index = 0; index < beforeAlls.length; index++) { 
  80.     beforeAlls[index].apply(this) 
  81.   } 
  82.   currDesc.name = desc 
  83.   fn.apply(this) 
  84.   for (var index = 0; index < afterAlls.length; index++) { 
  85.     afterAlls[index].apply(this) 
  86.   } 
  87.   stats.push(currDesc) 
  88.  
  89. exports.showTestsResults = function showTestsResults() { 
  90.     console.log(`Total Test: ${Totaltests}     
  91. Test Suites: passed, total 
  92. Tests: ${passedTests} passed, ${Totaltests} total 
  93. `) 
  94.   const logTitle = failedTests > 0 ? chalk.bgRed : chalk.bgGreen 
  95.   log(logTitle('Test Suites')) 
  96.   for (var index = 0; index < stats.length; index++) { 
  97.     var e = stats[index]; 
  98.     const descName = e.name 
  99.     const its = e.it 
  100.     log(descName) 
  101.     for (var i = 0; i < its.length; i++) { 
  102.       var _e = its[i]; 
  103.       log(`   ${_e.name}`) 
  104.       for (var ii = 0; ii < _e.expects.length; ii++) { 
  105.         const expect = _e.expects[ii] 
  106.         log(`      ${expect.status === true ? chalk.green('√') : chalk.red('X') } ${expect.name}`) 
  107.       } 
  108.     } 
  109.     log() 
  110.   } 
  111.  
  112. global.describe = describe 
  113. global.it = it 
  114. global.expect = expect 
  115. global.afterEach = afterEach 
  116. global.beforeEach = beforeEach 
  117. global.beforeAll = beforeAll 
  118. global.afterAll = afterAll 

在開(kāi)始的時(shí)候,我們需要使用chalk庫(kù),因?yàn)槲覀円盟鼇?lái)把失敗的測(cè)試寫(xiě)成紅色,把通過(guò)的測(cè)試寫(xiě)成綠色。我們將 console.log 縮短為 log。

接下來(lái),我們?cè)O(shè)置beforeEachs,afterEachs,afterAlls,beforeAlls的數(shù)組。beforeEachs將保存在它所附加的 it 函數(shù)開(kāi)始時(shí)調(diào)用的函數(shù);afterEachs將在它所附加的 it 函數(shù)的末尾調(diào)用;beforeEachs和afterEachs分別在 describe 函數(shù)的開(kāi)始和結(jié)尾處調(diào)用。

我們?cè)O(shè)置了 Totaltests 來(lái)保存運(yùn)行的測(cè)試數(shù)量, passTests 保存已通過(guò)的測(cè)試數(shù), failedTests 保存失敗的測(cè)試數(shù)。

stats 收集每個(gè)describe函數(shù)的stats, curDesc 指定當(dāng)前運(yùn)行的describe函數(shù)來(lái)幫助收集測(cè)試數(shù)據(jù), currIt 保留當(dāng)前正在執(zhí)行的 it 函數(shù),以幫助收集測(cè)試數(shù)據(jù)。

我們?cè)O(shè)置了beforeEach、afterEach、beforeAll和afterAll函數(shù),它們將函數(shù)參數(shù)推入相應(yīng)的數(shù)組,afterAll推入afterAlls數(shù)組,beforeEach推入beforeEachs數(shù)組,等等。

接下來(lái)是expect函數(shù),此函數(shù)進(jìn)行測(cè)試:

 
 
 
 
  1. expect(56).toBe(56) // 經(jīng)過(guò)測(cè)試56預(yù)期會(huì)是56 
  2. expect(func()).toEqual("nnamdi") // 該函數(shù)將返回一個(gè)等于“nnamdi”的字符串 

expect 函數(shù)接受一個(gè)要測(cè)試的參數(shù),并返回一個(gè)包含匹配器函數(shù)的對(duì)象。在這里,它返回一個(gè)具有 toBe 和 toEqual 函數(shù)的對(duì)象,它們具有期望參數(shù),用于與expect函數(shù)提供的value參數(shù)匹配。 toBe 使用 === 將value參數(shù)與期望參數(shù)匹配, toEqual 使用 == 測(cè)試期望值。如果測(cè)試通過(guò)或失敗,則這些函數(shù)將遞增 passedTests 和 failedTests 變量,并且還將統(tǒng)計(jì)信息記錄在currIt變量中。

我們目前只有兩個(gè)matcher函數(shù),還有很多:

  • toThrow
  • toBeNull
  • toBeFalsy
  • etc

你可以搜索它們并實(shí)現(xiàn)它們。

接下來(lái),我們有 it 函數(shù), desc 參數(shù)保存測(cè)試的描述名稱,而 fn 保存函數(shù)。它先對(duì)beforeEachs進(jìn)行fun,設(shè)置統(tǒng)計(jì),調(diào)用 fn 函數(shù),再調(diào)用afterEachs。

describe 函數(shù)的作用和 it 一樣,但在開(kāi)始和結(jié)束時(shí)調(diào)用 beforeAlls 和 afterAlls 。

showTestsResults 函數(shù)通過(guò) stats 數(shù)組進(jìn)行解析,并在終端上打印通過(guò)和失敗的測(cè)試。

我們實(shí)現(xiàn)了這里的所有函數(shù),并將它們都設(shè)置為全局對(duì)象,這樣才使得測(cè)試文件調(diào)用它們時(shí)不會(huì)出錯(cuò)。

回到“l(fā)ib/cli/cli.js”:

 
 
 
 
  1. // lib/cli/cli.js 
  2. const path = require('path') 
  3. const fs = require('fs') 
  4. const { showTestsResults } = require('./../') 

首先,它從“l(fā)ib/index”導(dǎo)入函數(shù) showTestsResult ,該函數(shù)將在終端顯示運(yùn)行測(cè)試文件的結(jié)果。另外,導(dǎo)入此文件將設(shè)置全局變量。

讓我們繼續(xù):

run 函數(shù)是這里的主要函數(shù),這里調(diào)用它,可以引導(dǎo)整個(gè)過(guò)程。它搜索 test 文件夾 searchTestFolder ,然后在數(shù)組 getTestFiles 中獲取測(cè)試文件,它循環(huán)遍歷測(cè)試文件數(shù)組并運(yùn)行它們 runTestFiles 。

  • searchTestFolder :使用 fs#existSync 方法檢查項(xiàng)目中是否存在“test/”文件夾。
  • getTestFiles :此函數(shù)使用 fs#readdirSync 方法讀取“test”文件夾的內(nèi)容并返回它們。
  • runTestFiles :它接受數(shù)組中的文件,使用 forEach 方法循環(huán)遍歷它們,并使用 require方法運(yùn)行每個(gè)文件。

kwuo文件夾結(jié)構(gòu)如下所示:

測(cè)試我們的框架

我們已經(jīng)完成了我們的測(cè)試框架,讓我們通過(guò)一個(gè)真實(shí)的Node項(xiàng)目對(duì)其進(jìn)行測(cè)試。

我們創(chuàng)建一個(gè)Node項(xiàng)目:

 
 
 
 
  1. mkdir examples 
  2. mkdir examples/math 
  3. cd examples/math 
  4. npm init -y 

創(chuàng)建一個(gè)src文件夾并添加add.js和sub.js

 
 
 
 
  1. mkdir src 
  2. touch src/add.js src/sub.js 

add.js和sub.js將包含以下內(nèi)容:

 
 
 
 
  1. // src/add.js 
  2. function add(a, b) { 
  3.     return a+b 
  4.  
  5. module.exports = add 
  6.  
  7. // src/sub.js 
  8. function sub(a, b) { 
  9.     return a-b 
  10.  
  11. module.exports = sub 

我們創(chuàng)建一個(gè)測(cè)試文件夾和測(cè)試文件:

 
 
 
 
  1. mkdir test 
  2. touch test/add.spec.js test/sub.spec.js 

規(guī)范文件將分別測(cè)試add.js和sub.js中的add和sub函數(shù)

 
 
 
 
  1. // test/sub.spec.js 
  2. const sub = require('../src/sub') 
  3. describe("Subtract numbers", () => { 
  4.   it("should subtract 1 from 2", () => { 
  5.     expect(sub(2, 1)).toEqual(1) 
  6.   }) 
  7.    
  8.   it("should subtract 2 from 3", () => { 
  9.     expect(sub(3, 2)).toEqual(1) 
  10.   }) 
  11. }) 
  12.  
  13. // test/add.spec.js 
  14. const add = require('../src/add') 
  15. describe("Add numbers", () => { 
  16.   it("should add 1 to 2", () => { 
  17.     expect(add(1, 2)).toEqual(3) 
  18.   }) 
  19.    
  20.   it("should add 2 to 3", () => { 
  21.     expect(add(2, 3)).toEqual(5) 
  22.   }) 
  23. }) 
  24. describe('Concat Strings', () => { 
  25.   let expected; 
  26.   beforeEach(() => { 
  27.     expected = "Hello"; 
  28.   }); 
  29.    
  30.   afterEach(() => { 
  31.     expected = ""; 
  32.   }); 
  33.    
  34.   it('add Hello + World', () => { 
  35.     expect(add("Hello", "World")) 
  36.       .toEqual(expected); 
  37.   }); 
  38. }); 

現(xiàn)在,我們將在package.json的“script”部分中運(yùn)行“test”以運(yùn)行我們的測(cè)試框架:

 
 
 
 
  1.   "name": "math", 
  2.   "version": "1.0.0", 
  3.   "description": "", 
  4.   "main": "index.js", 
  5.   "scripts": { 
  6.     "test": "kwuo" 
  7.   }, 
  8.   "keywords": [], 
  9.   "author": "Chidume Nnamdi ", 
  10.   "license": "ISC" 

我們?cè)诿钚猩线\(yùn)行 npm run test ,結(jié)果將是這樣的:

看,它給我們展示了統(tǒng)計(jì)數(shù)據(jù),通過(guò)測(cè)試的總數(shù),以及帶有“失敗”或“通過(guò)”標(biāo)記的測(cè)試套件列表??吹酵ㄟ^(guò)的測(cè)試期望“add Hello + World”,它將返回“HelloWorld”,但我們期望返回“Hello”。如果我們糾正它并重新運(yùn)行測(cè)試,所有測(cè)試都將通過(guò)。

 
 
 
 
  1. // test/add.spec.js 
  2. ... 
  3. describe('Concat Strings', () => { 
  4.   let expected; 
  5.   beforeEach(() => { 
  6.     expected = "Hello"; 
  7.   }); 
  8.    
  9.   afterEach(() => { 
  10.     expected = ""; 
  11.   }); 
  12.    
  13.   it('add Hello + World', () => { 
  14.     expect(add("Hello", "")) 
  15.       .toEqual(expected); 
  16.   }); 
  17. }); 

看,我們的測(cè)試框架像Jest和Jasmine一樣工作。它僅在Node上運(yùn)行,在下一篇文章中,我們將使其在瀏覽器上運(yùn)行。

代碼在Github上

Github倉(cāng)庫(kù)地址: philipszdavido/kwuoKwuo

你可以使用來(lái)自NPM的框架:

 
 
 
 
  1. cd IN_YOUR_NODE_PROJECT 
  2. npm install kwuo -D 

將package.json中的“test”更改為此:

 
 
 
 
  1.   ... 
  2.   "scripts": { 
  3.     "test": "kwuo" 
  4.     ... 
  5.   } 

總結(jié)

我們建立了我們的測(cè)試框架,在這個(gè)過(guò)程中,我們學(xué)會(huì)了如何使用全局來(lái)設(shè)置函數(shù)和屬性在運(yùn)行時(shí)任何地方可見(jiàn)。

我們看到了如何在項(xiàng)目中使用 describe 、 it 、 expect 和各種匹配函數(shù)來(lái)運(yùn)行測(cè)試。下一次,你使用Jest或Jasmine,你會(huì)更有信心,因?yàn)楝F(xiàn)在你知道它們是如何工作的。


網(wǎng)頁(yè)名稱:通過(guò)構(gòu)建自己的JavaScript測(cè)試框架來(lái)了解JS測(cè)試
當(dāng)前路徑:http://www.5511xx.com/article/djdpjjh.html