摘要:課堂互動(dòng)回調(diào)函數(shù)中運(yùn)行測(cè)試,調(diào)動(dòng)孩子們的課堂積極性。函數(shù),隨時(shí)記錄函數(shù)運(yùn)行狀態(tài)測(cè)試同步返回值異步返回值,就像是上課,這只是老師的本份。她平時(shí)混跡在普通學(xué)生之中,或者說,她就是一名再普通不過的學(xué)生。而最新的技術(shù)棧正在全面采用測(cè)試框架。
facebook三大項(xiàng)目:yarn jest metro,有橫掃宇宙之勢(shì)。 而jest項(xiàng)目的宗旨為:減少測(cè)試一個(gè)項(xiàng)目所花費(fèi)的時(shí)間成本和認(rèn)知成本。 ——其實(shí),它在讓你當(dāng)一個(gè)好老師。jest文檔非常簡(jiǎn)略、難以閱讀, 因此才有了這篇文章。 jest是vue、react和vue-cli技術(shù)棧的重要一環(huán),也是當(dāng)前最值得掌握的測(cè)試框架,對(duì)此你需要達(dá)到很熟悉的程度。
本文github地址: https://github.com/wanthering...
教育和測(cè)試,是相通的。
你可以野路子自學(xué),但掌握系統(tǒng)化、體系化的知識(shí),終歸離不開一個(gè)好老師。
測(cè)試可以不寫,但當(dāng)你面對(duì)大型復(fù)雜的項(xiàng)目之時(shí),沒有測(cè)試框架寸步難行。
現(xiàn)在,你可以跟我一步一步學(xué)會(huì)jest,你將懂得:為什么jest是優(yōu)雅、簡(jiǎn)潔而符合人性的,并且終將成為測(cè)試界的唯一的、最佳的解決方案。
第一課:jest的初步使用想象一下,當(dāng)你走上講臺(tái),五十多個(gè)孩子靜靜地看著你。紅撲撲的臉蛋,大大的眼睛。
接下來,你將課本上知識(shí)教給他們了一遍,
函數(shù)運(yùn)行過程,就相當(dāng)于你的教學(xué)過程。
請(qǐng)同學(xué)們跟我一起敲下代碼:
(請(qǐng)?jiān)陧?xiàng)目下創(chuàng)建一個(gè)文件:lesson1.js)
lesson1.js
/** * 加法,即是將多個(gè)數(shù)值逐個(gè)累加 */ exports.sum = (...args) => { let res = 0 for (let i of args) { res += i } return res } /** * 乘法,即是將b個(gè)重復(fù)的數(shù)值a,進(jìn)行累加 */ exports.times = (a, b) => { let resArr = (new Array(b)).fill(a) return exports.sum(...resArr) }
以上文件涉及es6和nodejs模塊化的基礎(chǔ)知識(shí),初看可能并不好理解,但相信我,你敲完以下的測(cè)試代碼,就會(huì)理解它的含義——就像教會(huì)一個(gè)學(xué)生一樣。
就像你js工程師面臨的永恒難題一樣——真的能跑通嗎?
當(dāng)老師的你,內(nèi)心也無比惶恐,第一次教這些,他們真的能懂嗎?
這時(shí)需要用上jest進(jìn)行測(cè)試,使用npm安裝:
npm i jest -S
一個(gè)合格的老師,會(huì)做這幾個(gè)步驟:
提問: 清晰地注明問題.
叫人回答: 給予一個(gè)函數(shù)體,運(yùn)行測(cè)試。
期待答案: expect()
校驗(yàn)答案: toBe()、toEqual()
創(chuàng)建一個(gè)lesson1.test.js
lesson1.test.js
const {sum, times} = require("./lesson1") test("同學(xué),請(qǐng)問這個(gè)累加的結(jié)果是什么?",()=>{ expect(sum(2+2+2+2+2+2)).toBe(12) }) test("同學(xué),請(qǐng)問這個(gè)乘法的結(jié)果是什么?",()=>{ expect(times(2,6)).toBe(12) }) test("那么,兩個(gè)數(shù)值的結(jié)果是否相等呢?",()=>{ expect(times(2,6)).toEqual(sum(2+2+2+2+2+2)) })運(yùn)行測(cè)試方法1:
這時(shí)需要運(yùn)行jest命令,你可以全局安裝jest:
npm i jest -g
然后
jest lesson1.test.js運(yùn)行測(cè)試方法2:
也可以在package json的test字段下寫入
... "scripts": { "test": "jest" }, ...
然后命令行輸入
npm test運(yùn)行測(cè)試方法3:
如果你使用的webstorm等IDE的話,文檔中直接顯示綠色小鍵頭,點(diǎn)擊就是了。
測(cè)試結(jié)果:接下來,會(huì)看到一路pass,證明lesson1.js文件無誤。
我們讀書這么多年,深知好老師和壞老師的區(qū)別:
上課照本宣科,就像直接寫下滿紙js代碼一樣,這是賴皮狗老師的專長(zhǎng)。
但一個(gè)優(yōu)秀的老師,他會(huì):
步步為營(yíng): 分解成很多個(gè)子測(cè)試,把知詞點(diǎn)逐個(gè)擊破。
版書清晰: 標(biāo)明需要測(cè)試什么,讓知識(shí)易學(xué)易記。
課堂互動(dòng): 回調(diào)函數(shù)中運(yùn)行測(cè)試,調(diào)動(dòng)孩子們的課堂積極性。
題型豐富: 通過匹配器,即toBe、toEqual等校驗(yàn)不同格式數(shù)據(jù)。
如果你不是很熟悉jest框架提供的各類匹配器,這里有一份小抄送給你:jest-cheat-sheet
你看,jest所做的,沒有一絲多余步驟,也沒少一個(gè)必要步驟,這正是我們這些年遇到的好老師的共有特征,也正是jest測(cè)試的極致之處。
第二課:異步測(cè)試獲取數(shù)據(jù)jest在異步過程中也非常方便!
我們先使用json-server建立服務(wù)器,再使用axios獲取數(shù)據(jù)。
這兩個(gè)npm包使用非常廣泛,熟悉的axios封裝的可以直接拷貝server.js和request.js代碼。
下載:
npm i json-server axios -S
創(chuàng)建server.js文件
server.js
const jsonServer = require("json-server") const defaultData = () => ({ "lesson": [ { "id": 1, "title": "how to add", "teacher": "Miss Wang" }, { "id": 2, "title": "how to multiply", "teacher": "Mr Liu" }, { "id": 3, "title": "how to subtract", "teacher": "Ms Han" } ], "homework": [ { "id": 1, "works": ["add","multiply"], "student": "Jim Green" }, { "id": 2, "title": ["add","subtract"], "student": "lily" }, { "id": 3, "title": ["add","subtract"], "student": "lucy" }, { "id": 4, "title": ["add","subtract","multiply"], "student": "Han Mei Mei" }, { "id": 5, "title": ["subtract","multiply"], "student": "Li Lei" } ], "exam": { "name": "primary school final exam" } }) const createJSONServer = (data = defaultData()) =>{ const server = jsonServer.create() const router = jsonServer.router(data) const middlewares = jsonServer.defaults() server.use(middlewares) server.use(router) return server } createJSONServer().listen(3000) console.log("3000端口已聯(lián)通")
創(chuàng)建request.js文件
request.js
const axios = require( "axios" ) class HttpRequest { constructor(baseUrl = "http://localhost:3000") { this.baseUrl = baseUrl } /** * 返回默認(rèn)配置 */ getInsideConfig() { return { baseURL: this.baseUrl, headers: {} } } /** * 響應(yīng)欄截,返回指定格式信息 */ interceptors(instance) { instance.interceptors.response.use(res => { const {data} = res return data }, error => { return Promise.reject(error) }) } /** * 處理網(wǎng)絡(luò)請(qǐng)求 */ request(options) { const instance = axios.create() options = Object.assign(this.getInsideConfig(), options) this.interceptors(instance) return instance(options) } } /** * 導(dǎo)出request模塊 */ exports.requestPromise = (port,method="get")=>{ const Http = new HttpRequest("http://localhost:3000") return Http.request({ url: port, method }) } exports.requestCallback = (cb,port,method="get")=>{ const Http = new HttpRequest("http://localhost:3000") Http.request({ url: port, method }).then(data=>{ // ▽請(qǐng)注釋掉下面一行,再試一試回調(diào)能否跑通? cb(data) }) }
使用node server跑起服務(wù),我們就可以開始測(cè)試異步回調(diào)了。
老師的困擾: 壞學(xué)生“異步回調(diào)函數(shù)”班上來了一個(gè)壞學(xué)生,上課從不好好聽課,偏偏人緣又特別好。
這時(shí),你提問讓壞學(xué)生回答,他只是安靜地站起來,什么都不做,然后過了一會(huì)對(duì)你說:“老師,這道題我回答過了??!”
同時(shí),全班同學(xué)都點(diǎn)頭“嗯嗯他回答過了”。
這時(shí)候,你,該怎么辦? 有沒有感受到深深的絕望?
看一看以下的例子。創(chuàng)建lesson2.test.js,并寫入
lesson2.test.js
const {requestPromise, requestCallback} = require("./request") test("異步callback方式檢測(cè)", () => { // 下面進(jìn)行了拋出了兩次斷言,在斷言之前可以 function callback (data){ expect(data).toStrictEqual({"id": 1, "title": "how to add", "teacher": "Miss Wang"}) } requestCallback(callback,"lesson/1") })
跑通了,似乎一切正常。。。
但當(dāng)我們回到request.js注釋掉cb(data)時(shí),我們知道回調(diào)函數(shù)并不返回?cái)?shù)據(jù),測(cè)試?yán)響?yīng)不通過。然而。。
還是跑通了!
這是因?yàn)閞equestCallback根本就沒有進(jìn)入函數(shù)體,而測(cè)試函數(shù),只要不報(bào)錯(cuò),都算通過。
異步回調(diào),就是這樣一個(gè)壞透了的學(xué)生,經(jīng)常裝作回答過了蒙混過關(guān)。
異步回調(diào)的正確測(cè)試方法:作為老師,弄死壞學(xué)生的方法可能你自己想到了:
“上黑板寫,寫完告訴我!”
你可以提供一個(gè)在測(cè)試函數(shù)內(nèi)提供一個(gè)done,done必須要調(diào)用后,才能算做測(cè)試通過。
lesson2.test.js
test("異步callback方式檢測(cè)", done => { // 下面進(jìn)行了拋出了兩次斷言,在斷言之前可以 function callback (data){ expect(data).toStrictEqual({"id": 1, "title": "how to add", "teacher": "Miss Wang"}) done() } requestCallback(callback,"lesson/1") })
這樣,就必須要運(yùn)行了callback才能通過測(cè)試了,否則就會(huì)超時(shí)報(bào)錯(cuò)。
除了以上方式以外,你還可以檢驗(yàn)函數(shù)體內(nèi)的斷言跑了幾次
test("異步callback方式檢測(cè),無done", () => { // 下面進(jìn)行了拋出了兩次斷言,在斷言之前可以 expect.assertions(1); function callback (data){ expect(data).toStrictEqual({"id": 1, "title": "how to add", "teacher": "Miss Wang"}) } requestCallback(callback,"lesson/1") })
expect.assertions(1)表示, 斷言語句expect(xxx).toXXX(xxx)必須跑通一次,將要檢驗(yàn)多個(gè)“壞學(xué)生”異步回調(diào)的時(shí)候,這招猶其有效。
普通學(xué)生:異步Promise有壞學(xué)生,自然有好學(xué)和普通學(xué)生,promise就是一名“普通的學(xué)生”
lesson2.test.js
test("異步Promise方式檢測(cè)", () => { expect.assertions(1); return requestPromise("exam").then(data => { expect(data).toStrictEqual({"name": "primary school final exam"}) }) })
檢驗(yàn)異步Promise時(shí),必須要用return返回,否則它就像“壞學(xué)生”一樣,直接蒙混過關(guān)溜走了。
你還可以使用使用.resolve/.reject形式
lesson2.test.js
test("異步Promise方式被成功resolve", () => { expect.assertions(1); return expect(requestPromise("exam")).resolves.toStrictEqual({"name": "primary school final exam"}) });
如果需要檢驗(yàn)Promise被reject:
test("異步Promise方式被reject", () => { expect.assertions(1); return expect(requestPromise("exam")).rejects.toMatch("error") });三好學(xué)生:async/await異步
上課從不遲到、校服永遠(yuǎn)一塵不染、作業(yè)按時(shí)永遠(yuǎn)上交、上課認(rèn)真做筆記、回答問題天衣無縫、別人不聽課她還會(huì)打!小!報(bào)!告!
這就是我們的async/await,我們應(yīng)該多一些這樣的三好學(xué)生。
lesson2.test.js
test("異步async/await方式檢測(cè)", async () => { // 下面進(jìn)行了拋出了兩次斷言,在斷言之前可以 expect.assertions(2) const lesson1 = await requestPromise("lesson/1") const homework3 = await requestPromise("homework/3") expect(lesson1).toStrictEqual({"id": 1, "title": "how to add", "teacher": "Miss Wang"}) expect(homework3).toMatchObject({"student": "lucy"}) })
優(yōu)雅,舒適、簡(jiǎn)潔、大方,無需多言,async/await值得你擁有。
雖然我們很多時(shí)候還是在和異步回調(diào)、異步Promise打交道...
第三課:Mock函數(shù),袖口五道杠的風(fēng)紀(jì)委員假如不是簡(jiǎn)單的測(cè)試同步返回、測(cè)試異步返回,而是需要記錄執(zhí)行過程中的狀態(tài)呢?
const forEach = (arr, fn) => { if (!arr.length || !fn) return let i = -1 let len = arr.length while (++i < len) { let item = arr[i] fn(item, i, arr) } }
假如遇到這樣一個(gè)循環(huán)函數(shù),內(nèi)部的運(yùn)行狀態(tài)就不太可能通過返回值來知曉了。這時(shí),你需要Mock函數(shù)。
Mock函數(shù),隨時(shí)記錄函數(shù)運(yùn)行狀態(tài)測(cè)試同步返回值、異步返回值,就像是上課,這只是老師的本份。
而學(xué)生大部分時(shí)間,都是自習(xí)、吃飯、宿舍,老師想管到這一部分,就需要派出讓人聞風(fēng)喪臉的存在——五道杠·無間道·小報(bào)告之王·風(fēng)紀(jì)委員。
她平時(shí)混跡在普通學(xué)生之中,或者說,她就是一名再普通不過的學(xué)生。但,當(dāng)她遇到老師——即在test()測(cè)試體內(nèi)——一點(diǎn)兒陳芝麻爛谷的破事,都會(huì)被抖露出來。
lesson3.test.js
//通過jest.fn()創(chuàng)建Mock Function const mockCallback = jest.fn(x => 42 + x); //將mockCallback代入forEach運(yùn)行一次,即可記錄下所有的值 forEach([0, 1], mockCallback); test("記錄mockCallback函數(shù)運(yùn)行過程",()=>{ // mockCallback上報(bào)函數(shù)運(yùn)行了兩次 expect(mockCallback.mock.calls.length).toBe(2); // mockCallback上報(bào)函數(shù)第一次運(yùn)行的輸入為0 expect(mockCallback.mock.calls[0][0]).toBe(0); // mockCallback上報(bào)函數(shù)第二次運(yùn)行的輸入為1 expect(mockCallback.mock.calls[1][0]).toBe(1); // The return value of the first call to the function was 42 // mockCallback上報(bào)函數(shù)第一次運(yùn)行的結(jié)果為42 expect(mockCallback.mock.results[0].value).toBe(42); })結(jié)語
提起教師,隨處可見的朋友圈、公眾號(hào)、賀卡
短信里面,盡是雞湯般的口號(hào):“人類靈魂工程師”、“燃燒自己,照亮他人”“無私”“奉獻(xiàn)”“愛心”。
但,教師的本職——最高效率地輔助學(xué)生構(gòu)建的完整知識(shí)體系。 專業(yè)性的觀點(diǎn)卻被選擇性忽視。
軟件開發(fā)也是,人人在談測(cè)試驅(qū)動(dòng),人人都在強(qiáng)調(diào)測(cè)試的重要性,測(cè)試似乎成了一個(gè)形而上學(xué)的感性概念。
但時(shí)間和人力成本上、框架的專業(yè)性、框架的掌握成本的諸多限制,使大多數(shù)項(xiàng)目測(cè)試相當(dāng)于無。另一方面,少數(shù)高度測(cè)試覆蓋的項(xiàng)目又顯得十分笨拙,測(cè)試耗費(fèi)的精力居然比coding還長(zhǎng)...
幸之,得益于jest測(cè)試框架的產(chǎn)生,一個(gè)極致簡(jiǎn)潔
功能強(qiáng)大、語義清晰的測(cè)試終于呈現(xiàn)在我們面前。讓開發(fā)與測(cè)試相輔相成,而非時(shí)間加倍。
而最新的vue技術(shù)棧正在全面采用jest測(cè)試框架。
從此,testing之對(duì)于coding,如同孤獨(dú)的鋼琴曲中,緩緩傳來小提琴的和弦,頓時(shí)錦瑟和鳴,心靈震顫無以復(fù)加。
前面我已經(jīng)介紹了AST抽象語法樹,點(diǎn)擊鏈接地址,下一期,將結(jié)合AST帶來測(cè)試驅(qū)動(dòng)開發(fā)實(shí)戰(zhàn),這,將是讀懂vue-cli3、并掌握vue全方位技術(shù)棧的第一步。vue-cli3技術(shù)棧補(bǔ)全預(yù)告:
[x] AST抽象語法樹: 童年的玩具
[x] jest測(cè)試框架: 行為人師,學(xué)為世范
jest測(cè)試驅(qū)動(dòng)開發(fā)實(shí)戰(zhàn): js配置文件的更新
yaml配置文件: 至愛之信
config文件導(dǎo)入全配置: 萬能鑰匙
vue-share-utils:實(shí)用小工具
Generator: vue-cli3核心引擎,機(jī)械之心
jest+Generator: 測(cè)試驅(qū)動(dòng)vue-cli3引擎
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/97774.html
摘要:年工程化協(xié)作開發(fā)棧最佳實(shí)踐我們將花半小時(shí)實(shí)戰(zhàn)擼一個(gè)包含,的標(biāo)準(zhǔn)的用于工程協(xié)作的包開發(fā)棧。使用腳手架,秒鐘構(gòu)建可自由配置的開發(fā)棧。分別表示詢問彈窗自動(dòng)執(zhí)行任務(wù)執(zhí)行任務(wù)后操作。 發(fā)起一個(gè)github/npm工程協(xié)作項(xiàng)目,門檻太高了??! 最基礎(chǔ)的問題,你都要花很久去研究: 如何在項(xiàng)目中全線使用es2017代碼? 答案是babel 如何統(tǒng)一所有協(xié)作者的代碼風(fēng)格? 答案是eslint + pr...
摘要:社區(qū)簡(jiǎn)介一個(gè)人可以走得很快,一群人才能走得更遠(yuǎn)。作為過來人,我們每一位社區(qū)管理人員都深知?jiǎng)偛饺氪髮W(xué)的同學(xué)都會(huì)經(jīng)歷迷茫時(shí)期,不是不想學(xué)習(xí),而是不知道該怎么學(xué),從何學(xué)起,時(shí)間就在悄然間流逝。 ...
摘要:?jiǎn)卧獪y(cè)試針對(duì)程序模塊進(jìn)行測(cè)試。是開源的單元測(cè)試工具。一個(gè)好的單元測(cè)試應(yīng)該具備的條件安全重構(gòu)已有代碼單元測(cè)試一個(gè)很重要的價(jià)值是為重構(gòu)保駕護(hù)航。斷言外部依賴單元測(cè)試的一個(gè)重要原則就是無依賴和隔離。 前端測(cè)試金字塔 對(duì)于一個(gè) Web 應(yīng)用來說,理想的測(cè)試組合應(yīng)該包含大量單元測(cè)試(unit tests),部分快照測(cè)試(snapshot tests),以及少量端到端測(cè)試(e2e tests)。參...
摘要:?jiǎn)卧獪y(cè)試前端的單元測(cè)試目前有兩個(gè)比較熱的框架,一個(gè)是的方式,一個(gè)是。小伙伴們不用急,關(guān)于單元測(cè)試這塊,我會(huì)找時(shí)間寫博客的。首先前端的測(cè)試分為兩種,一個(gè)是單元測(cè)試,另一個(gè)就是測(cè)試了。? ? ? ? 因?yàn)楣卷?xiàng)目要用vue框架,所以會(huì)用vue-cli來新建項(xiàng)目。用過vue的都知道,要全局安裝vue以及腳手架vue-cli,然后執(zhí)行vue init webpack projectname來新建vu...
摘要:學(xué)習(xí)之道簡(jiǎn)體中文版通往實(shí)戰(zhàn)大師之旅掌握最簡(jiǎn)單,且最實(shí)用的教程。前言學(xué)習(xí)之道這本書使用路線圖中的精華部分用于傳授,并將其融入一個(gè)獨(dú)具吸引力的真實(shí)世界的具體代碼實(shí)現(xiàn)。完美展現(xiàn)了的優(yōu)雅。膜拜的學(xué)習(xí)之道是必讀的一本書。 《React 學(xué)習(xí)之道》The Road to learn React (簡(jiǎn)體中文版) 通往 React 實(shí)戰(zhàn)大師之旅:掌握 React 最簡(jiǎn)單,且最實(shí)用的教程。 showIm...
閱讀 1877·2019-08-30 15:53
閱讀 3204·2019-08-30 15:44
閱讀 2812·2019-08-26 13:31
閱讀 1957·2019-08-26 12:10
閱讀 802·2019-08-26 11:01
閱讀 2133·2019-08-23 15:32
閱讀 1590·2019-08-23 13:43
閱讀 2545·2019-08-23 11:58