斷言是編程術語,表示爲一些布爾表達式,程序員相信在程序中的某個特定點該表達式值爲真,能夠在任什麼時候候啓用和禁用斷言驗證,所以能夠在測試時啓用斷言而在部署時禁用斷言。一樣,程序投入運行後,最終用戶在遇到問題時能夠從新啓用斷言。程序員
使用斷言能夠建立更穩定、品質更好且 不易於出錯的代碼。當須要在一個值爲FALSE時中斷當前操做的話,可使用斷言。【單元測試】必須使用斷言。正則表達式
Node提供了 10 多個斷言測試的函數,用於測試不變式,我在文章中將這 10 多個函數進行了分組,方便理解記憶。編程
【提示】在本文章中,expected 表明預期值,actual 表明實際值, message 表明自定義信息函數
判斷值是否爲真值有如下兩個斷言測試函數單元測試
這個測試函數在 【Boolean(value)】 爲 【true】時經過斷言測試,不然拋出 【AssertionError】測試
const assert = require("assert"); assert("blue","第一個值爲false時以我爲錯誤信息拋出"); assert(true,"第一個值爲false時以我爲錯誤信息拋出");
上面一段代碼因爲【Boolean(value)】所有爲 true,因此所有經過斷言測試ui
assert(false,"第一個值爲false時以我爲錯誤信息拋出"); // AssertionError [ERR_ASSERTION]: 第一個值爲false時以我爲錯誤信息拋出
上面代碼中 value 爲false,則拋出一個帶有 message 屬性的 【AssertionError】,其中 message 屬性的值等於傳入的 message 參數的值。 【若是 message 參數爲 undefined,則賦予默認的錯誤信息】。.net
assert(false); // AssertionError [ERR_ASSERTION]: false == true
上面代碼因爲沒有指定【message】參數,拋出的爲默認錯誤信息的【AssertionError】code
assert.ok() 與 assert()的做用是同樣的,都是測試【value】是否爲真值。並且用法也同樣,因此能夠將assert()視爲assert.ok()的語法糖對象
const assert = require("assert"); assert.ok(true); assert.ok(1);
上面代碼【Boolean(value)】所有爲 true,因此所有斷言經過,下面是斷言不經過的狀況,分別列出了默認錯誤信息
assert.ok(0); //AssertionError [ERR_ASSERTION]: 0 == true assert.ok(false); //AssertionError [ERR_ASSERTION]: false == true assert.ok(false,"自定義錯誤信息"); //AssertionError [ERR_ASSERTION]: 自定義錯誤信息
這一組裏面有兩個測試函數,用於測試預期值與實際值是否相等,若是相等則斷言經過,不然拋出 【AssertionError】
assert.equal()用於測試指望值和實際值是否相等,【在值類型的時候比較的是兩個值是否相等,當預期值和實際值爲引用類型的時候,比較的是值得引用】
assert.equal(1, 1); assert.equal("1", 1);
上面代碼是對值類型進行的比較,說明equal()在內部使用的是(==),而非嚴格相等,待會兒我會總結到嚴格相等(===)
assert.equal({},{},"AssertionError"); assert.equal(() => { }, () => { }, "AssertionError"); assert.equal([],[],'AssertionError');
上面三個表達式都會拋出【message】屬性值爲'AssertionError'的【AssertionError】對象,【因此當值爲引用類型的時候,equal()比較的是值得引用,所以兩個引用類型的值是無法經過equal()斷言的】
const obj={}; assert.equal(obj,obj); // 斷言經過
上面代碼因爲比較的是同一個對象,兩個值得引用相等,因此斷言經過。
一樣也是測試 預期值 和 實際值 是否相等,使用的仍然是(==),可是與equal不一樣的是,【deepEqual()在對引用類型進行比較的時候,不是對值的引用進行比較,而是比較的對象的屬性值】
const a = 'Blue', b = 'Pink'; assert.deepEqual(a,a,'actual unequal to expected'); // 斷言經過 assert.deepEqual(a,b,'actual unequal to expected'); // AssertionError [ERR_ASSERTION]: actual unequal to expected
上面是對值類型進行的比較,和equal()沒有任何的區別
const obj1 = { name: "foo", gender: "men" }, obj2 = { name: "foo", gender: "men" }, obj3 = { name: "bar", gender: "men" } assert.deepEqual(obj1, obj2, 'actual unequal to expected'); // 斷言經過 assert.deepEqual(obj1, obj3, 'actual unequal to expected'); // AssertionError [ERR_ASSERTION]: actual unequal to expected
上面代碼是對引用類型的比較,能夠看出【deepEqual()】比較的是屬性值,而非引用,這是與equal()不一樣的地方。
【注意!!】deepEqual()只測試可枚舉的自身屬性,不測試對象的原型、鏈接符、或不可枚舉的屬性(這些狀況使用 assert.deepStrictEqual(),稍後會總結到)
const son1 = Object.create(obj1), son2 = Object.create(obj2); son1.name="Summer"; son2.name="Summer"; assert.deepEqual(son1,son2,"actual unequal to expected"); // 斷言經過
上面代碼中 son1 和 son2 分別繼承與兩個不一樣的對象,都擁有 name 爲 「Summer」 的屬性,最後的的結果是經過,說明【deepEqual()不測試對象的原型】
const ena = {}, enb = {}; Object.defineProperties(ena,{ name:{ value:"Blue" }, hobby:{ value:"foo", enumerable:false //可枚舉性設置爲false } }); Object.defineProperties(enb,{ name:{ value:"Blue" }, hobby:{ value:"bar", enumerable:false //可枚舉性設置爲false } }) assert.deepEqual(ena,enb,"actual unequal to expected") //ok,actual equal to expected
上面代碼中 ena 和 enb 用於相同的可枚舉屬性【name】,有着值不一樣的不可枚舉屬性【hobby】,說明【deepEqual()不測試對象的不可枚舉的屬性】
這組測試函數是用於判斷預期值和實際值是否深度相等的,內部使用的是(===),因此對象的原型也會進行比較,值得類型也是比較的範圍。這組也有兩個測試函數。
因爲內部使用的是全等(===),因此對象的原型也會計入比較的範圍
const obj1 = { name: "foo", gender: "men" }, obj2 = { name: "bar", gender: "men" } const son1 = Object.create(obj1), son2 = Object.create(obj2); son1.name = "Summer"; son2.name = "Summer"; assert.deepEqual(son1, son2, "actual unequal to expected"); //斷言經過 assert.deepStrictEqual(son1, son2, "actual unequal to expected") //AssertionError [ERR_ASSERTION]: actual unequal to expected
上面代碼使用了deepEqual()和deepStrictEqual()進行了斷言測試,son1 和 son2 分別繼承與兩個不一樣的對象,可是擁有相同的屬性值。能夠看出【deepEqual()是不會考慮對象的原型的,deepStrictEqual()將原型對象列入了比較對象】
strictEqual()是equal()的增強,考慮了數據類型;若是actual === expected,則斷言經過,不然拋出AssertionError,message?message:默認錯誤信息。
assert.strictEqual(1, 2); // 拋出 AssertionError: 1 === 2 assert.strictEqual(1, 1); // 測試經過。 assert.strictEqual(1, '1'); // 拋出 AssertionError: 1 === '1' assert.equal(1, '1'); // 測試經過。
【提示!!】對引用類型仍是永遠通不過【strictEqual()】斷言測試
上面總結到了判斷預期值和實際值相等,這兒總結一下判斷預期值和實際值不想等的兩個測試函數,實際上就是上面 (三) 的逆運算。
【notEqual()】爲 【equal()】的逆運算,若是 actual!= expected 則斷言經過,一樣對於值類型是單純對值進行比較,對應引用類型比較的是值得引用
assert.notEqual("1", "2"); // 斷言經過 assert.notEqual("1", 2); // 斷言經過 assert.notEqual("1", 1); // AssertionError [ERR_ASSERTION]: '1' != 1
上面代碼是對值類型進行的比較,第三個表達式的默認信息能夠看出內部使用的是(!=)
assert.notEqual({ a: "foo" }, { a: "foo" }); assert.notEqual(() => { }, () => { }); assert.notEqual([], []);
上面的代碼是對引用類型進行的斷言測試,【notEqual()】對於兩個對象的測試經過是一個【恆成立】的結果。
【notDeepEqual()】爲 【deepEqual()】的逆運算,若是 actual!= expected 則斷言經過,不一樣於notEqual()的是對於引用類型是對值進行判斷,不比對原型、不可枚舉屬性,只比對自有可枚舉屬性,斷言經過。
const obj1 = { a: "foo" }, obj2 = { b: "bar" }, obj3 = Object.create(obj1); assert.notDeepEqual(obj1,obj1,'actual equal to expected'); // AssertionError [ERR_ASSERTION]: actual equal to expected assert.notDeepEqual(obj1,obj2,'actual equal to expected'); // 斷言經過 assert.notDeepEqual(obj1,obj3,'actual equal to expected'); // 斷言經過
上面代碼中最後一個表達式斷言經過,說明【不比對原型、不可枚舉屬性,只比對自有可枚舉屬性】
【注意!!】與notEqual的區別,也就是deepEqual和equal的區別,在引用數據類型的時候,deepEqual是比較的值而非引用,equal對比的是引用,因此引用類型在equal的時候是永遠沒法經過斷言測試的,以此類推,引用類型在notEqual時是永遠否能夠經過斷言測試的。
上面總結到了判斷預期值和實際值嚴格相等,這兒總結一下判斷預期值和實際值嚴格不相等的兩個測試函數,實際上就是上面 (四) 的逆運算。
若是actual與expected不 !== 則斷言經過, 與 assert.deepStrictEqual() 相反
assert.notStrictEqual("1", 1); // 斷言經過 assert.notStrictEqual("1", "1"); // AssertionError [ERR_ASSERTION]: '1' !== '1'
上面代碼是對值類型進行的斷言測試,能夠看出【notStrictEqual()】考慮了數據類型
assert.notStrictEqual({ a: "foo" }, { a: "foo" }); assert.notStrictEqual(() => { }, () => { }); assert.notStrictEqual([], []);
上面代碼是對引用類型的測試,所有經過,以上表達式是恆經過的。
notDeepStrictEqual()就是deepStrictEqual()的逆運算,若是 actual !== expected 則斷言經過,不然拋出AssertionError。
assert.notDeepStrictEqual({ a: '1' }, { a: 1 }); //斷言經過 assert.notDeepStrictEqual({ a: '1' }, { a: "1" }); //AssertionError [ERR_ASSERTION]: { a: '1' } notDeepStrictEqual { a: '1' }
這一組有 四 個(能夠說是 三 個)測試函數,是對錯誤進行的處理。
這個測試函數很少說,能夠看錯是下一個函數的重載,用於主動拋出帶有【message】屬性的【AssertionError】對象
assert.fail("自定義錯誤信息"); // AssertionError [ERR_ASSERTION]: 自定義錯誤信息
該測試函數用於主動拋出自定義錯誤信息,拋出錯誤信息格式:【actual 參數 + operator 參數 + expected 參數】
assert.fail("BLUE","PINK"); // AssertionError [ERR_ASSERTION]: 'BLUE' != 'PINK'
上面代碼不提供【message】和【operator】,則【operator】默認爲 【!=】
assert.fail("BLUE","PINK","自定義的錯誤信息"); // AssertionError [ERR_ASSERTION]: 自定義的錯誤信息 assert.fail("BLUE","PINK","自定義的錯誤信息","?",()=>{ console.log("hello"); }); // AssertionError [ERR_ASSERTION]: 自定義的錯誤信息
上面代碼提供【message】,這時候 【actual】、【operator】、【expected】等參數會被列入錯誤對象屬性中
assert.fail("BLUE","PINK",undefined); // AssertionError [ERR_ASSERTION]: 'BLUE' undefined 'PINK' assert.fail("BLUE","PINK",undefined,"?"); // AssertionError [ERR_ASSERTION]: 'BLUE' ? 'PINK'
上面代碼是【message】爲 undefined 時,會檢測【operator】參數,【operator?operator:undefined 】
參數說明:
【說明!!】若是block拋出的錯誤知足error參數,也就是拋出錯誤與指望一致,則斷言經過,不然拋出block中的錯誤,若是block不拋出錯誤,則拋出【AssertionError 】。
【提示!!】error 參數能夠是構造函數、正則表達式、或自定義函數。
assert.throws( () => { throw new Error('錯誤信息'); }, Error );
上面代碼中 error 參數爲構造函數,【block】拋出的錯誤與預期的一致,因此斷言經過。
assert.throws( () => { throw new Error('錯誤信息'); }, /錯誤/ );
上面代碼中 error 參數爲正則表達式,【block】拋出的錯誤知足正則表達式,因此斷言經過。
【注意!!】error 參數不能是字符串。 若是第二個參數是字符串,則視爲省略 error 參數,傳入的字符串會被用於 【message】 參數,
// 這是錯誤的!不要這麼作! assert.throws(myFunction, '錯誤信息', '沒有拋出指望的信息'); // 應該這麼作。 assert.throws(myFunction, /錯誤信息/, '沒有拋出指望的信息');
下面代碼,【error】 參數爲自定義函數
assert.throws( () => { throw new Error('錯誤信息'); }, function (err) { if ((err instanceof Error) && /錯誤/.test(err)) { return true; } }, '不是指望的錯誤' );
【說明!!】預期的錯誤和實際的錯誤一致時,不拋出實際錯誤,拋出AssertionError,不一致則拋出實際錯誤信息
assert.doesNotThrow( () => { throw new TypeError('錯誤信息'); }, SyntaxError );
以上例子會拋出 TypeError,由於在斷言中沒有匹配的錯誤類型
assert.doesNotThrow( () => { throw new TypeError('錯誤信息'); }, TypeError );
以上例子會拋出一個帶有 Got unwanted exception (TypeError).. 信息的 AssertionError
assert.doesNotThrow( () => { throw new TypeError('錯誤信息'); }, TypeError, '拋出錯誤' ); // 拋出 AssertionError: Got unwanted exception (TypeError). 拋出錯誤
上面代碼說明:若是拋出了 AssertionError 且有給 message 參數傳值,則 message 參數的值會被附加到 AssertionError 的信息中
這兒只有一個測試函數了
若是value的值爲真或者能夠轉換成true,則拋出value,不然斷言經過。
assert.ifError(true); //拋出true assert.ifError(false); //斷言經過
上面代碼中是直接給出的 布爾 類型的值,若是值爲 true 則會將該值拋出,不然什麼也不作
assert.ifError(0); //斷言經過 assert.ifError("0"); //拋出 "0" assert.ifError(1); //拋出 1 assert.ifError(new Error()); //拋出 Error,對象名稱
上面代碼中所有是經過 Boolean(value) 轉換以後再進行的測試,利用這個特性咱們能夠將此測試函數用於測試回調函數的 error 參數。
--------------------------END--------------------------
CSDN【Node斷言assert】同步更新