摘要:?jiǎn)卧獪y(cè)試,測(cè)試一個(gè)簡(jiǎn)單的組件。接口測(cè)試,用戶信息接口測(cè)試。學(xué)習(xí)借鑒,一些使用做測(cè)試的開(kāi)源項(xiàng)目。這里使用到的內(nèi)置斷言斷言結(jié)果值等于我們想要的預(yù)期值,則測(cè)試通過(guò)。在里放入一個(gè)函數(shù),函數(shù)自動(dòng)執(zhí)行,里面執(zhí)行的結(jié)果必須拋出錯(cuò)誤,則測(cè)試通過(guò)。
目錄
1、為什么選擇 AVA ?
2、API 概覽。
3、準(zhǔn)備工作。
4、單元測(cè)試,測(cè)試一個(gè)簡(jiǎn)單的工具函數(shù)。
5、使用 Promise、Async/await、Observable 。
6、使用 JSDOM 模擬瀏覽器環(huán)境。
7、單元測(cè)試,測(cè)試一個(gè)簡(jiǎn)單的 React 組件。
8、Http 接口測(cè)試,GitHub 用戶信息接口測(cè)試。
9、串行測(cè)試。
10、快照斷言。
11、覆蓋率報(bào)告:nyc + Coveralls 。
12、持續(xù)集成:CircleCI 。
13、學(xué)習(xí)借鑒,一些使用 AVA 做測(cè)試的開(kāi)源項(xiàng)目。
14、e2e測(cè)試框架推薦:TestCafe 。
15、參考。
原子測(cè)試 - 名詞的鏈接屬于自己猜測(cè),不知作者本人是否也是表達(dá)這個(gè)意思。
斷言 - 通俗的講,就是用來(lái)判斷 “ 函數(shù)的返回值 ” 與我們想要的值是否一致,一致則測(cè)試通過(guò),不一致則不通過(guò)。
1、輕量,高效,簡(jiǎn)單。
2、并發(fā)測(cè)試,強(qiáng)制編寫(xiě)原子測(cè)試。
3、沒(méi)有隱藏的全局變量,每個(gè)測(cè)試文件獨(dú)立環(huán)境。
4、支持 ES2017,Promise,Generator,Async,Observable。
5、內(nèi)置斷言,強(qiáng)化斷言信息。
6、可選的 TAP 輸出顯示。
7、為什么不用 Mocha,Tape,Tap?
官方文檔解釋:https://github.com/avajs/ava#faq
一些測(cè)試框架的對(duì)比:https://github.com/koajs/koa/...
API 概覽test([title], implementation) 基本測(cè)試 test.serial([title], implementation) 串行運(yùn)行測(cè)試 test.cb([title], implementation) 回調(diào)函數(shù)形式 test.only([title], implementation) 運(yùn)行指定的測(cè)試 test.skip([title], implementation) 跳過(guò)測(cè)試 test.todo(title) 備忘測(cè)試 test.failing([title], implementation) 失敗的測(cè)試 test.before([title], implementation) 鉤子函數(shù),這個(gè)會(huì)在所有測(cè)試前運(yùn)行 test.after([title], implementation) 鉤子函數(shù),這個(gè)會(huì)在所有測(cè)試之后運(yùn)行 test.beforeEach([title], implementation) 鉤子函數(shù),這個(gè)會(huì)在每個(gè)測(cè)試之前運(yùn)行 test.afterEach([title], implementation) 鉤子函數(shù),這個(gè)會(huì)在每個(gè)測(cè)試之后運(yùn)行 test.after.always([title], implementation) 鉤子函數(shù),這個(gè)會(huì)在所有測(cè)試之后運(yùn)行,不管之前的測(cè)試是否失敗 test.afterEach.always([title], implementation) 鉤子函數(shù),這個(gè)會(huì)在每個(gè)測(cè)試之后運(yùn)行,不管之前的測(cè)試是否失敗內(nèi)置斷言
也可以用 chai, node assert 等其他斷言庫(kù)
.pass([message]) 測(cè)試通過(guò) .fail([message]) 斷言失敗 .truthy(value, [message]) 斷言 value 是否是真值 .falsy(value, [message]) 斷言 value 是否是假值 .true(value, [message]) 斷言 value 是否是 true .false(value, [message]) 斷言 value 是否是 false .is(value, expected, [message]) 斷言 value 是否和 expected 相等 .not(value, expected, [message]) 斷言 value 是否和 expected 不等 .deepEqual(value, expected, [message]) 斷言 value 是否和 expected 深度相等 .notDeepEqual(value, expected, [message]) 斷言 value 是否和 expected 深度不等 .throws(function|promise, [error, [message]]) 斷言 function 拋出一個(gè)異常,或者 promise reject 一個(gè)錯(cuò)誤 .notThrows(function|promise, [message]) 斷言 function 沒(méi)有拋出一個(gè)異常,或者 promise resolve .regex(contents, regex, [message]) 斷言 contents 匹配 regex .notRegex(contents, regex, [message]) 斷言 contents 不匹配 regex .ifError(error, [message]) 斷言 error 是假值 .snapshot(expected, [message]) 將預(yù)期值與先前記錄的快照進(jìn)行比較 .snapshot(expected, [options], [message]) 將預(yù)期值與先前記錄的快照進(jìn)行比較準(zhǔn)備工作
務(wù)虛已過(guò),編寫(xiě)測(cè)試用例之前我們需要先安裝 AVA。
先全局安裝:npm i --global ava
再在項(xiàng)目根目錄安裝一次:npm i --save-dev ava
這是通俗的安裝方式,全局安裝方便 AVA 自身命令行調(diào)用,不用太糾結(jié)。
像我們剛剛說(shuō)的,AVA 已經(jīng)內(nèi)置支持 ES2017 的語(yǔ)法,安裝 AVA 的時(shí)候已經(jīng)幫我們安裝了一些關(guān)于 babel 的模塊,不過(guò)我們還再安裝幾個(gè)我們需要用到的 babel 模塊,如下。
npm i --save-dev babel-polyfill babel-preset-es2015 babel-preset-react babel-preset-stage-0
babel-polyfill // 包含 ES2015 及以后的功能函數(shù),如:Object.assign babel-preset-es2015 // 支持 ES2015 語(yǔ)法 babel-preset-react // 支持 React 語(yǔ)法 babel-preset-stage-0 // 支持 ECMA TC39 對(duì) JS 語(yǔ)言定義的最早一個(gè)階段的想法的語(yǔ)法
關(guān)于 AVA 的一些基礎(chǔ)配置的意思,可以查看一下官方文檔。
實(shí)際用到的配置也不多,我們?cè)?package.json 文件中配置一下 AVA :
"scripts": { "test": "ava --verbose" // 添加測(cè)試命令,方便我們直接輸入一小段命令 npm test。--verbose 表示輸出的測(cè)試信息盡量詳細(xì) }, "ava": { "babel": "inherit", // 繼承已有的 babel 配置,就是繼承我們下面 .babelrc 的文件配置 "require": [ // 每個(gè)測(cè)試前,先加載 require 里面的模塊 "babel-register", // 默認(rèn)引入的,安裝 AVA 時(shí)已經(jīng)自帶安裝好 "babel-polyfill" ] }
在項(xiàng)目根目錄創(chuàng)建 .babelrc 文件, 并輸入以下內(nèi)容:
這里的坑在于,如果不創(chuàng)建 .babelrc 文件,而是把 babel 的配置寫(xiě)在 package.json 里,在使用 import 導(dǎo)入 React 組件時(shí),會(huì)報(bào)語(yǔ)法錯(cuò)誤。
可使用命令行創(chuàng)建文件:touch .babelrc
{ "presets": ["es2015", "stage-0", "react"] }
看看現(xiàn)在的目錄結(jié)構(gòu)是怎么樣的:
在 test 目錄創(chuàng)建一個(gè) simple_test.js 文件,內(nèi)容如下
import test from "ava"; function trimAll(string) { return string.replace(/[s]/g, ""); } test("trimAll testing", t => { // 字符串內(nèi)含有空格符、制表符等空字符都應(yīng)刪除 t.is(trimAll(" v f B a r r i o r v f "), "Barrior"); // 無(wú)空字符時(shí),輸出值應(yīng)為輸入值 t.is(trimAll("Barrior"), "Barrior"); // 輸入 new String 對(duì)象應(yīng)與輸入基本類型字符串結(jié)果相同 t.is(trimAll(new String(" T o m ")), "Tom"); // 輸入其他非字符串?dāng)?shù)據(jù)類型時(shí),應(yīng)拋出錯(cuò)誤 [undefined, null, 0, true, [], {}, () => {}, Symbol()].forEach(type => { t.throws(() => { trimAll(type); }); }); });
test():執(zhí)行一個(gè)測(cè)試,第一個(gè)參數(shù)為標(biāo)題,第二參數(shù)為測(cè)試用例函數(shù),接收一個(gè)包含內(nèi)置斷言 API 的參數(shù) t,也是唯一一個(gè)參數(shù);按照慣例這個(gè)參數(shù)名字叫做 t,沒(méi)必要重新取名字。
這里使用到的內(nèi)置斷言:
t.is(resultValue, expected), 斷言結(jié)果值等于我們想要的預(yù)期值,則測(cè)試通過(guò)。全等判斷。
t.throws(function), 在 throws 里放入一個(gè)函數(shù),函數(shù)自動(dòng)執(zhí)行,里面執(zhí)行的結(jié)果必須拋出錯(cuò)誤,則測(cè)試通過(guò)。
運(yùn)行 npm test,可以看到如下結(jié)果,一個(gè)測(cè)試用例通過(guò)。
改動(dòng)一下測(cè)試用例,看看測(cè)試不通過(guò)是怎么樣的。
t.is(trimAll("Barrior123"), "Barrior");
運(yùn)行 npm test
紅色框框就是我們說(shuō)的強(qiáng)化斷言信息,將結(jié)果值與預(yù)期值進(jìn)行了差異對(duì)比,幫助我們定位錯(cuò)誤。
使用 Promise、Async/await、ObservablePromise、Async/await 都是語(yǔ)法層面的東西,Observable 還沒(méi)深入了解過(guò),
語(yǔ)法糖的代碼就不貼來(lái)占用空間了,可以下載示例代碼看看就會(huì)了。
Observable 這里的坑在于需要引入 RxJS: npm i --save rxjs,官方文檔并沒(méi)有說(shuō)明。
import test from "ava"; import {Observable} from "rxjs"; test(t => { t.plan(3); return Observable .of(1, 2, 3, 4, 5, 6) .filter(n => { return n % 2 === 0; }) .map(() => t.pass()); });使用 JSDOM 模擬瀏覽器環(huán)境
安裝 JSDOM 模塊:npm i --save-dev jsdom
在目錄下創(chuàng)建一個(gè) jsdom.js 文件,內(nèi)容如下:
import test from "ava"; import {JSDOM} from "jsdom"; const html = ``; const {window} = new JSDOM(html, {runScripts: "dangerously"}); const document = window.document; test("emulate DOM environment with JSDOM", t => { const textarea = document.querySelector(".comment-box textarea"); const btn = document.querySelector(".btn"); const list = document.querySelector(".list"); const text = "hello world"; btn.click(); // 觸發(fā)按鈕的點(diǎn)擊事件,此時(shí)文本框中沒(méi)有輸入內(nèi)容 t.is(list.children.length, 0); // 列表應(yīng)該保持為空 textarea.value = text; // 文本框中輸入內(nèi)容 btn.click(); // 觸發(fā)按鈕的點(diǎn)擊事件 t.is(list.children.length, 1); // 此時(shí)列表的長(zhǎng)度應(yīng)該為 1 t.is(list.children[0].innerHTML, text); // 此時(shí),第一個(gè)評(píng)論的內(nèi)容應(yīng)該等于剛剛我們輸入的內(nèi)容 t.falsy(textarea.value); // 評(píng)論完后,文本框應(yīng)該清空 });發(fā)布
簡(jiǎn)單介紹 JSDOM API。
new JSDOM(html, {runScripts: "dangerously"}); :創(chuàng)建一個(gè) DOM 環(huán)境,可以傳入完整的 HTML 文檔,也可以值傳入一行 HTML 文檔聲明,如:。
參數(shù) runScripts: "dangerously" 表示讓文檔里的 JavaScript 可以運(yùn)行,默認(rèn)禁止運(yùn)行。
創(chuàng)建后返回一個(gè)對(duì)象,里面包含一個(gè) window 對(duì)象,我們便是需要用到這個(gè) window 對(duì)象,及其屬性 document 對(duì)象,用在我們的測(cè)試。
更多使用方法和配置可以查看一下官方文檔。
測(cè)試?yán)锩娴拇a就是原生的 JavaScript DOM 操作代碼。
單元測(cè)試,測(cè)試一個(gè)簡(jiǎn)單的 React 組件測(cè)試 React 組件需要依賴 JSDOM, 所以我們放在這里講。
安裝需要依賴的一些模塊:npm i --save react react-dom, npm i --save-dev enzyme react-test-renderer。這里也不用糾結(jié)為什么一會(huì)用 --save, 一會(huì)用 --save-dev, 因?yàn)?--save 表示這些模塊在線上項(xiàng)目也需要用到,而 --save-dev 表示這些模塊只用作開(kāi)發(fā)或者測(cè)試等,線上項(xiàng)目不需要用到這些模塊。
Enzyme 是一個(gè) React 測(cè)試工具,可以說(shuō)是把 React 組件渲染在我們測(cè)試的環(huán)境里,不需要依賴真實(shí)的瀏覽器。
Enzyme 依賴 react-test-renderer,React >=15.5 安裝 react-test-renderer,其它版本安裝 react-addons-test-utils
在 src 目錄下創(chuàng)建 todo.js 文件,內(nèi)容如下,一個(gè)簡(jiǎn)單的備忘錄組件:
import React from "react"; import ReactDOM from "react-dom"; export default class Todo extends React.Component { constructor(props) { super(props); this.state = { names: props.names || [] }; } add() { const elem = this.refs.textarea; const name = elem.value; if (name) { elem.value = ""; this.state.names.push(name); this.setState({}); } else { elem.focus(); } } del(i) { this.state.names.splice(i, 1); this.setState({}); } render() { return () } }{ this.state.names.map((name, i) => { return (
- Member name: {name}
) }) }
在 test 目錄下創(chuàng)建一個(gè) helpers 文件夾,并在文件夾里面創(chuàng)建 setup_dom_env.js 文件, 內(nèi)容如下。
AVA 的規(guī)則會(huì)忽略 helpers 文件夾,不會(huì)將里面的文件當(dāng)做測(cè)試文件執(zhí)行。
import {JSDOM} from "jsdom"; const dom = new JSDOM(""); global.window = dom.window; global.document = dom.window.document; global.navigator = dom.window.navigator;
這就是 React 組件需要依賴的 JSDOM 模擬的 DOM 環(huán)境的代碼。
需要將 window、document、navigator 等對(duì)象掛載到 global 對(duì)象上,組件才能運(yùn)行。
在 test 目錄下創(chuàng)建 react_component.js, 內(nèi)容如下,先引入模擬 DOM 環(huán)境的文件。
import "./helpers/setup_dom_env"; import test from "ava"; import React from "react"; import {mount} from "enzyme"; import Todo from "../src/todo"; test("actual testing for react component", t => { const wrapper = mount(); // 讓組件運(yùn)行,返回一個(gè)對(duì)象 const list = wrapper.find("ul"); // 從對(duì)象里找到 render 里的 DOM 元素 ul t.is(list.find("li").length, 2); // 斷言備忘錄有 2 條記錄 wrapper.find("textarea").node.value = "Lily"; // 文本框?qū)懭胫? wrapper.find("textarea + button").simulate("click"); // 觸發(fā)按鈕的點(diǎn)擊事件 t.is(list.find("li").length, 3); // 斷言備忘錄有 3 條記錄 });
簡(jiǎn)單介紹 Enzyme API
mount: 表示渲染組件的時(shí)候支持生命周期,個(gè)人覺(jué)得測(cè)試時(shí)一般都會(huì)用這個(gè),因?yàn)檎鎸?shí)組件生命周期的調(diào)用是極為平常的事。
Enzyme API 和 jQuery API 很相似,會(huì) jQuery 應(yīng)該很容易理解。
Http 接口測(cè)試,GitHub 用戶信息接口測(cè)試打開(kāi)接口:https://api.github.com/users/...,返回用戶的一些基本信息,有些字段值是動(dòng)態(tài)改變的,用戶修改即變,這樣的動(dòng)態(tài)字段我們可以查詢數(shù)據(jù)庫(kù)來(lái)對(duì)比。這里我們以一個(gè)假設(shè)不變的 login 字段來(lái)演示。
先安裝 Request 模塊: npm i --save-dev request,方便發(fā)送 http 請(qǐng)求。
在 test 目錄下創(chuàng)建 http.js, 內(nèi)容如下。
import test from "ava"; import request from "request"; // test.cb() 回調(diào)函數(shù)形式測(cè)試異步代碼,異步結(jié)束調(diào)用 t.end() test.cb("http api testing", t => { // 基于 Request API 創(chuàng)建 http 請(qǐng)求的配置 const options = { baseUrl: "https://api.github.com", url: "/users/Barrior", // 請(qǐng)求超時(shí)時(shí)間 timeout: 5 * 1000, // http 請(qǐng)求頭部,模擬得跟瀏覽器越像越好,不然被服務(wù)器處理成爬蟲(chóng)或者其他就可能得不到我們想要的響應(yīng) headers: { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36" } }; // Request API 發(fā)送 GET 請(qǐng)求 request.get(options, (err, res, body) => { if (err) t.fail("服務(wù)器響應(yīng)超時(shí)!"); if (res && res.statusCode === 200) { body = JSON.parse(body); t.is(body.login, "Barrior"); } else { t.fail("無(wú)響應(yīng)內(nèi)容或狀態(tài)碼錯(cuò)誤!"); } // 異步結(jié)束 t.end(); }); });
運(yùn)行 npm test,可以看到測(cè)試通過(guò)。
很多情況并行測(cè)試就好,但某些場(chǎng)景我們需要測(cè)試按順序一個(gè)接一個(gè)的執(zhí)行,即使是異步,并且后面的測(cè)試可能依賴前面測(cè)試的結(jié)果,這時(shí)就需要用到串行測(cè)試,test.serial()。
在 test 目錄下創(chuàng)建 serial.js, 內(nèi)容如下,一個(gè)簡(jiǎn)單的串行測(cè)試演示。
import test from "ava"; const globalData = {}; test.serial("serial testing: step one", t => { return new Promise(resolve => { setTimeout(() => { globalData.name = "Barrior"; t.pass(); resolve(); }, 500); }); }); test("serial testing: step two", t => { t.is(globalData.name, "Barrior"); });
這里只是 serial.js 文件串行執(zhí)行,如果想所有文件都串行執(zhí)行,需要在命令行傳遞 --serial 標(biāo)志。
快照斷言t.snapshot(expected, [options]), 將預(yù)期值與先前記錄的快照進(jìn)行比較。
第一次運(yùn)行測(cè)試,快照斷言會(huì)將預(yù)期值存儲(chǔ)起來(lái),待第二次及以后運(yùn)行測(cè)試,則拿已經(jīng)存儲(chǔ)好的快照與新的預(yù)期值進(jìn)行比較,吻合則測(cè)試通過(guò),否則測(cè)試失敗。
一般用于預(yù)期值比較龐大的情況,如:Html 模板,React 渲染出來(lái)的模板,或許還可以用于 Http 接口返回的一堆數(shù)據(jù)。
如下,做個(gè)簡(jiǎn)單演示。
import test from "ava"; function getUserInfo(uid) { return [{ id: 0, name: "Barrior", sex: "male" }, { id: 1, name: "Tom", sex: "male" }][uid] } function renderUserDom(uid) { const userInfo = getUserInfo(uid); return `覆蓋率報(bào)告:nyc + Coveralls `; } test("snapshot", t => { const user1 = renderUserDom(0); const user2 = renderUserDom(1); // 自定義 id 必須是一個(gè)字符串或者 buffer // 不定義,AVA 會(huì)默認(rèn)生成一個(gè) id t.snapshot(user1, {id: "1"}); t.snapshot(user2, {id: "2"}); });
安裝模塊 nyc 和 coveralls:npm i --save-dev nyc coveralls
擴(kuò)展測(cè)試命令,前面加個(gè) nyc 即可:"test": "nyc ava --verbose"
測(cè)試覆蓋率是基于文件被測(cè)試的情況來(lái)反饋出指標(biāo),所以我們把 simple_test.js 里的 trimAll 函數(shù)多帶帶提出來(lái)作為一個(gè)文件,放到 src 目錄,命名為 trim_all.js。
運(yùn)行 npm test,簡(jiǎn)潔的覆蓋率報(bào)告如下。
Stmts: Statement 的縮寫(xiě),語(yǔ)句覆蓋,通常指某一行代碼是否被測(cè)試覆蓋了,不包括注釋,條件等。
Branch: 分支覆蓋或條件覆蓋,指某一個(gè)條件語(yǔ)句是否被測(cè)試覆蓋了,如:if、while;分支數(shù)是條件語(yǔ)句的兩倍。
Funcs: Function 的縮寫(xiě),函數(shù)覆蓋,指這個(gè)函數(shù)是否被測(cè)試代碼調(diào)用了。
Lines: 行覆蓋,通常情況等于語(yǔ)句覆蓋。一行未必只有一條語(yǔ)句(官方給的差異解釋):https://github.com/gotwarlost...
這里有一篇關(guān)于這幾個(gè)指標(biāo)的具體解釋和演示說(shuō)明,和對(duì)做覆蓋率報(bào)告的思考:http://www.infoq.com/cn/artic...
如果想看具體報(bào)告的信息,可以輸出成 html 文檔來(lái)瞧瞧,如下添加輸出報(bào)告命令。
"scripts": { ... "report": "nyc report --reporter=html" }
運(yùn)行 npm run report,coverage 目錄就會(huì)生成一些相關(guān)文件,瀏覽器打開(kāi) index.html,就可以看到如下內(nèi)容。
點(diǎn)擊文件進(jìn)去,可以查看該文件測(cè)試覆蓋的詳情。
Coveralls一個(gè)將項(xiàng)目覆蓋率展示到網(wǎng)頁(yè)上,適合開(kāi)源項(xiàng)目。
網(wǎng)址:https://coveralls.io
先注冊(cè)登錄,然后在項(xiàng)目根目錄添加 .coveralls.yml,內(nèi)容如下。
service_name: travis-ci repo_token: 你自己的項(xiàng)目 token, Coveralls 網(wǎng)站提供的私有令牌
添加上傳命令。
"scripts": { ... "coverage": "nyc report --reporter=text-lcov | coveralls" }
運(yùn)行 npm run coverage,等待報(bào)告上傳完畢,就可以在網(wǎng)站上看到報(bào)告。
持續(xù)集成:CircleCI通俗的講,持續(xù)集成就是每次提交代碼,自動(dòng)化程序就自動(dòng)構(gòu)建(包括編譯,發(fā)布,自動(dòng)化測(cè)試等)來(lái)驗(yàn)證代碼,從而盡早地發(fā)現(xiàn)代碼中的錯(cuò)誤。
網(wǎng)址:https://circleci.com/,適合開(kāi)源項(xiàng)目。
在項(xiàng)目根目錄添加 circle.yml 文件,內(nèi)容如下,配置項(xiàng)都可以在文檔中找到。
# 配置 NodeJS 的版本為 7 machine: node: version: 7 # 安裝依賴的命令 dependencies: override: - npm i -g ava - npm i # 運(yùn)行的測(cè)試命令 test: override: - npm test
使用 GitHub 賬號(hào)登錄 CircleCI 網(wǎng)站,選擇持續(xù)集成這個(gè)項(xiàng)目,這里我們用的是 1.0 平臺(tái),不要選 2.0,因?yàn)榕渲玫膶?xiě)法不一樣。
至此,每次提交代碼到這個(gè)項(xiàng)目,CircleCI 就會(huì)自動(dòng)幫我們集成。
完成了覆蓋率和持續(xù)集成,這兩個(gè)網(wǎng)站都提供了小徽章給我們,類似如下,可以貼到項(xiàng)目中以顯某種態(tài)度。
pageres
postcss-discard-comments
postcss-selector-parser
download
jparticles
e2e測(cè)試框架推薦:TestCafe官網(wǎng)地址:https://devexpress.github.io/...
推薦理由(缺點(diǎn)須躬行):
無(wú)需配置繁瑣的環(huán)境。
基于 NodeJS 生態(tài)。
參考http://i5ting.github.io/ava-p...
https://github.com/avajs/ava
文中的代碼托放于 GitHub,可供參考。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/84508.html
摘要:前同事留下的測(cè)試,是基于瀏覽器的,主要還是功能測(cè)試。這里不詳細(xì)說(shuō)怎么在瀏覽器端使用測(cè)試了。而且作者也是建議和支持這樣做的,簡(jiǎn)單明了的測(cè)試腳本,重要性有時(shí)候可能和測(cè)試本身一樣重要。經(jīng)測(cè)試,在瀏覽器也有這種問(wèn)題。 2016-09-03 更新 隨著在工作學(xué)習(xí)中更多地接觸、使用測(cè)試工具,發(fā)現(xiàn)自己在本文中的一些記錄是不準(zhǔn)確、不正確的。 今天(九月三日)在家看了 NingJs 的直播,其中有一個(gè)分...
摘要:翻譯瘋狂的技術(shù)宅原文本文首發(fā)微信公眾號(hào)歡迎關(guān)注,每天都給你推送新鮮的前端技術(shù)文章本文描述了通過(guò)生成包的最小設(shè)置。是用于轉(zhuǎn)換的預(yù)設(shè)。有關(guān)這兩個(gè)屬性的更多信息設(shè)置多平臺(tái)包。表示使用上一節(jié)中的配置。結(jié)論以上是通過(guò)創(chuàng)建包最小庫(kù)的方法。 翻譯:瘋狂的技術(shù)宅原文:http://2ality.com/2017/07/npm... 本文首發(fā)微信公眾號(hào):jingchengyideng歡迎關(guān)注,每天都...
摘要:現(xiàn)在,我們可以使用單元測(cè)試來(lái)提高自己的代碼質(zhì)量。它在單元測(cè)試的編寫(xiě)中通常用來(lái)模擬等相關(guān)請(qǐng)求。通過(guò)這篇文章,你應(yīng)該學(xué)會(huì)了如何針對(duì)已有代碼從零開(kāi)始編寫(xiě)一套完整的單元測(cè)試用例。 概述 在日常的功能開(kāi)發(fā)中,我們的代碼測(cè)試都依賴于自己或者QA進(jìn)行測(cè)試。這些操作不僅費(fèi)時(shí)費(fèi)力,而且還依賴開(kāi)發(fā)者自身的驅(qū)動(dòng)。在開(kāi)發(fā)一些第三方依賴的庫(kù)時(shí),我們也沒(méi)有辦法給第三方提供完整的代碼質(zhì)量報(bào)告。 現(xiàn)在,我們可以使用單...
摘要:你將看到它們的語(yǔ)法時(shí)時(shí)關(guān)注它們的進(jìn)展與更新。標(biāo)準(zhǔn)有個(gè)版本,個(gè)發(fā)布第個(gè)版本被放棄了。此建議的目的只是避免在起草建議被放棄或發(fā)生重大帶來(lái)的麻煩。如果使用過(guò)度,將導(dǎo)致性能下降。在這個(gè)場(chǎng)景中,數(shù)字和空字符串都被認(rèn)為是假的。 showImg(https://segmentfault.com/img/bVbj2Az?w=2000&h=1333); 想閱讀更多優(yōu)質(zhì)文章請(qǐng)猛戳GitHub博客,一年百來(lái)...
摘要:在,是當(dāng)之無(wú)愧的王者,贏得了與之間的戰(zhàn)爭(zhēng),攻陷了的城池。于月發(fā)布了版本,這一版本為了更好的表現(xiàn)加入了渲染方式。前端框架這個(gè)前端框架清單可能是年疲勞的元兇之一。的創(chuàng)建者,目前在工作為尋找構(gòu)建簡(jiǎn)單性和自主配置性之間的平衡做了很大的貢獻(xiàn)。 春節(jié)后的第一篇就從這個(gè)開(kāi)始吧~本文已在前端早讀課公眾號(hào)上首發(fā) 原文鏈接 JavasScript社區(qū)在創(chuàng)新的道路上開(kāi)足了馬力,曾經(jīng)流行過(guò)的也許一個(gè)月之后就過(guò)...
閱讀 1234·2021-09-22 15:43
閱讀 2430·2021-09-22 15:32
閱讀 4677·2021-09-22 15:11
閱讀 2347·2019-08-30 15:55
閱讀 2723·2019-08-30 15:54
閱讀 1047·2019-08-30 15:44
閱讀 1189·2019-08-29 13:26
閱讀 873·2019-08-29 12:54