摘要:基本上,測試金字塔描述你應該編寫單元測試集成測試和端到端測試。集成測試要比端到端測試多,單元測試甚至要更多一些。應用程序單元測試編寫單元測試,是為了看看給定的模塊單元是否工作。
本文轉載自:眾成翻譯
譯者:網絡埋伏紀事
鏈接:http://www.zcfy.cc/article/1754
原文:https://blog.risingstack.com/node-hero-node-js-unit-testing-tutorial/
本教程將會學習 Node.js 中的單元測試是什么,以及如何正確地測試你的應用程序。
測試 Node.js 應用程序你可以把測試當作你創建的應用程序的保障措施。他們將不僅運行在你的本機上,還會在 CI 服務上,這樣失敗的構建就不會推送到產品系統中。
你也許會問:我的應用程序中該測試什么?我應該有多少測試?
答案因情而異,但是根據經驗,你可以遵循測試金字塔制定的準則。
基本上,測試金字塔描述你應該編寫單元測試、集成測試和端到端測試。集成測試要比端到端測試多,單元測試甚至要更多一些。
下面我們來看看如何為應用程序添加單元測試!
請注意,這里我們不打算討論集成測試和端到端測試,因為它們遠遠超出了本教程的范疇。
*
Node.js 應用程序單元測試編寫單元測試,是為了看看給定的模塊(單元)是否工作。所有依賴都被剔除了,意味著我們要為模塊提供偽依賴。
應該為指定模塊暴露的方法,而不是內部操作提供測試。
單元測試剖析每個單元測試有如下結構:
測試設置
調用被測試的方法
斷言
每個單元測試應該只測試一個關注點。(當然,這不意味著你可以只添加一個斷言)。
用于 Node.js 單元測試的模塊對于單元測試,我們打算用如下模塊:
測試運行器: mocha,或者 tape
斷言庫: chai, 或者 assert 模塊 (用于斷言)
測試 spy、stub 以及 mock: sinon (用于測試設置)。
Spy、stub 和 mock - 用哪一個以及什么時候用?在動手寫單元測試之前,我們先看看什么是 spy、stub 和 mock!
可以使用 spy 來獲取函數調用上的信息,比如函數被調用了多少次,或者傳遞了什么參數給它們。
it("calls subscribers on publish", function () { var callback = sinon.spy() PubSub.subscribe("message", callback) PubSub.publishSync("message") assertTrue(callback.called) }) // 采用的示例來自于 sinon 文檔網站: http://sinonjs.org/docs/
Stub(樁)與 spy 類似,但是它是替換目標函數??梢允褂?stub 來控制一個方法的行為,從而強制一個代碼路徑(比如拋出異常),或者阻止對外部資源的調用(比如 HTTP API)。
it("calls all subscribers, even if there are exceptions", function (){ var message = "an example message" var error = "an example error message" var stub = sinon.stub().throws() var spy1 = sinon.spy() var spy2 = sinon.spy() PubSub.subscribe(message, stub) PubSub.subscribe(message, spy1) PubSub.subscribe(message, spy2) PubSub.publishSync(message, undefined) assert(spy1.called) assert(spy2.called) assert(stub.calledBefore(spy1)) }) // 采用的示例來自于 sinon 文檔網站: http://sinonjs.org/docs/
mock 是帶有預先編好的行為和期望值的偽方法。
it("calls all subscribers when exceptions happen", function () { var myAPI = { method: function () {} } var spy = sinon.spy() var mock = sinon.mock(myAPI) mock.expects("method").once().throws() PubSub.subscribe("message", myAPI.method) PubSub.subscribe("message", spy) PubSub.publishSync("message", undefined) mock.verify() assert(spy.calledOnce) // 采用的示例來自于 sinon 文檔網站: http://sinonjs.org/docs/ })
如你所見,對于 mock,你必須預先定義好期望的值。
*
假設要測試如下的模塊:
const fs = require("fs") const request = require("request") function saveWebpage (url, filePath) { return getWebpage(url, filePath) .then(writeFile) } function getWebpage (url) { return new Promise (function (resolve, reject) { request.get(url, function (err, response, body) { if (err) { return reject(err) } resolve(body) }) }) } function writeFile (fileContent) { let filePath = "page" return new Promise (function (resolve, reject) { fs.writeFile(filePath, fileContent, function (err) { if (err) { return reject(err) } resolve(filePath) }) }) } module.exports = { saveWebpage }
這個模塊做一件事情:將網頁(基于指定的 URL)保存為本機上的一個文件。要測試該模塊,我們必須拔掉 fs 模塊和 request 模塊。
在我們 RisingStack 團隊中,在真正開始為本模塊編寫單元測試前,我們通常添加一個 test-setup.spec.js 文件來做基礎測試設置,比如創建 sinon 沙箱。這樣可以省下每次測試后編寫 sinon.sandbox.create() 和 sinon.sandbox.restore()。
// test-setup.spec.js const sinon = require("sinon") const chai = require("chai") beforeEach(function () { this.sandbox = sinon.sandbox.create() }) afterEach(function () { this.sandbox.restore() })
此外,請注意,我們總是將測試文件放在挨著實現文件的地方,所以就有了 .spec.js 這個名稱。在我們的 package.json 文件中,可以找到這些行:
{ "test-unit": "NODE_ENV=test mocha "/**/*.spec.js"", }
有了這些設置后,就可以寫測試本身了!
const fs = require("fs") const request = require("request") const expect = require("chai").expect const webpage = require("./webpage") describe("The webpage module", function () { it("saves the content", function * () { const url = "google.com" const content = "title
" const writeFileStub = this.sandbox.stub(fs, "writeFile", function (filePath, fileContent, cb) { cb(null) }) const requestStub = this.sandbox.stub(request, "get", function (url, cb) { cb(null, null, content) }) const result = yield webpage.saveWebpage(url) expect(writeFileStub).to.be.calledWith() expect(requestStub).to.be.calledWith(url) expect(result).to.eql("page") }) })
完整的代碼庫在這里找到:https://github.com/RisingStack/nodehero-testing
代碼覆蓋率要了解你的代碼庫被測試覆蓋的情況,你可以生成一個覆蓋率報告。
這個報告將包含如下指標:
行覆蓋率
語句覆蓋率
分支覆蓋率
函數覆蓋率
在 RisingStack 公司中,我們使用 istanbul 計算代碼覆蓋率。你應該將如下腳本添加到 package.json 文件中,來在 mocha 中使用 istanbul:
istanbul cover _mocha $(find ./lib -name "*.spec.js" -not -path "./node_modules/*")
之后,你將得到像這樣的代碼覆蓋率報告:
你可以點擊一下,看看帶注解的源代碼 - 哪些部分被測試,哪些部分沒有。
下一步測試可以省下很多麻煩 - 不過,依然不可避免要時常調試。下一章將學習如何調試 Node.js 應用程序。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/85167.html
摘要:本文轉載自眾成翻譯譯者網絡埋伏紀事鏈接原文本教程中將學習如何使用和實現一個本地身份驗證策略。我們將有一個用戶頁,一個備注頁,和一些與身份驗證相關的功能。下一步下一章主要涉及應用程序的單元測試。你會學習單元測試測試金字塔測試替代等概念。 本文轉載自:眾成翻譯譯者:網絡埋伏紀事鏈接:http://www.zcfy.cc/article/1755原文:https://blog.risings...
摘要:使用一個事件驅動的非阻塞式的模型,讓它輕量而高效。也就是說提供了用編寫服務器的可能性,這種服務器具有令人難以置信的性能。正如官方聲明所說是一個使用與瀏覽器相同引擎的運行時。這意味著有兩個發布版本穩定版和試驗版。 本文轉載自:眾成翻譯譯者:網絡埋伏紀事鏈接:http://www.zcfy.cc/article/1748原文:https://blog.risingstack.com/nod...
摘要:本教程會學習如何正確組織一個項目的結構,從而在應用程序開始增長時避免混亂。項目結構的五個基本規則組織項目有不少可能的方式并且每種已知的方式都有其興衰。過去在,我們有機會創建各種規模的高效應用程序,也獲得了大量關于項目結構注意事項的見解。 本文轉載自:眾成翻譯譯者:網絡埋伏紀事鏈接:http://www.zcfy.cc/article/1756原文:https://blog.rising...
摘要:網站和使用同樣的注冊庫來顯示模塊以及查找模塊。使用在上一章開始使用中,當創建文件時,已經遇到了。此外,全局命名空間只包含公共模塊。通過引入作用域包來解決此問題。下一步異步編程下一章學習使用回調和實現異步編程的原理。 本文轉載自:眾成翻譯譯者:網絡埋伏紀事鏈接:http://www.zcfy.cc/article/1749原文:https://blog.risingstack.com/n...
摘要:是一種設計用于關系型數據庫的查詢語言。另一方面,數據庫在最近十年變得相當流行。大多數數據庫都有驅動程序可以用,它們在上也有庫。我們已經完成了在中使用數據庫所必須知道的所有基礎知識。 本文轉載自:眾成翻譯譯者:網絡埋伏紀事鏈接:http://www.zcfy.cc/article/1751原文:https://blog.risingstack.com/node-js-database-t...
閱讀 1762·2021-10-12 10:12
閱讀 2530·2021-09-29 09:42
閱讀 2711·2021-09-03 10:28
閱讀 2249·2019-08-30 15:54
閱讀 1153·2019-08-30 15:53
閱讀 1388·2019-08-30 11:26
閱讀 3357·2019-08-30 11:02
閱讀 2134·2019-08-30 11:02