布解讀:更智能的默認(rèn)值、統(tǒng)一字符串 API 與更精確的調(diào)度器)
開發(fā)工具測試【免費下載鏈接】fast-checkProperty based testing framework for JavaScript (like QuickCheck) written in TypeScript項目地址https://gitcode.com/gh_mirrors/fa/fast-check點擊查看免費下載fast-check 4.0.0 標(biāo)志著 3.x 系列的終結(jié)也是該屬性測試Property Based Testing框架在 API 精簡、現(xiàn)代標(biāo)準(zhǔn)擁抱與去 polyfill 化上的關(guān)鍵里程碑。本文基于倉庫中的官方發(fā)布說明Whats new in fast-check 4.0.0?與遷移指南From 3.x to 4.x并結(jié)合源碼實現(xiàn)逐項展開幫助你在升級到 v4 時準(zhǔn)確理解每一項破壞性變更的動機(jī)、替代寫法與底層原理。版本背景基于 3.23.2 的 4.0.0v4.0.0 直接基于 v3.23.2 構(gòu)建見 CHANGELOG.md 中的 4.0.0 小節(jié)官方將本次發(fā)布定位為縮減 API 表面積讓 fast-check 的上手更簡單Reducing the API surface to ease ramp-up on fast-check。官方建議的遷移路徑是先升級到最新的 3.x 小版本處理其中已有的 deprecation 提示再切換到 4.x——因為大部分破壞性變更廢棄 API 的移除、新默認(rèn)值在 3.x 的后期小版本中就已以非破壞方式鋪墊完畢。官方給出的最小環(huán)境要求變化如下名稱新要求舊要求Node≥12.17.0≥8ECMAScript 規(guī)范ES2020ES2017TypeScript可選≥5.0≥4.1這一點在當(dāng)前倉庫中可以得到印證packages/fast-check/package.json 中聲明了engines: { node: 12.17.0 }即構(gòu)建與運行都強(qiáng)制 Node 不低于 12.17.0。三大核心變化Key Takeaways發(fā)布說明將 4.0.0 概括為三項核心變化更智能的默認(rèn)值Smarter defaults、統(tǒng)一的字符串構(gòu)建器Unified string builder、更精細(xì)的調(diào)度器Finer scheduler。下面逐項展開。1. 更智能的默認(rèn)值Invalid Date 與無原型對象4.0.0 延續(xù)提供更具挑戰(zhàn)性的默認(rèn)行為的思路date默認(rèn)開始生成 Invalid Daterecord/dictionary/object默認(rèn)可能生成null原型對象。官方目標(biāo)是在用戶替他們預(yù)判邊界場景讓測試者專注于規(guī)格定義本身。date 默認(rèn)包含 Invalid Date。從 date.ts 的實現(xiàn)可以看到其機(jī)制約束接口中noInvalidDate的默認(rèn)值為false源碼注釋明確defaultValue false當(dāng)未禁用時實現(xiàn)把生成區(qū)間從[intMin, intMax]擴(kuò)展為[intMin, intMax 1]用額外的一個整數(shù)值valueForNaN intMax 1映射出 Invalid Date并配有可逆的 unmapper 用于 shrink。若你的被測代碼無法處理 Invalid Date顯式加回約束即可-fc.date(); fc.date({ noInvalidDate: true });record / dictionary 默認(rèn)包含 null 原型。v3 時代這兩個 arbitrary 生成的對象總繼承自常規(guī)Object原型v4 起默認(rèn)行為改為可能是 null 原型對象。如果代碼要求對象必須有常規(guī)原型可將noNullPrototype置為true該選項自 3.13.0 引入v3 中默認(rèn)是truev4 中反轉(zhuǎn)為 falsefc.dictionary(fc.string(), fc.string(), { noNullPrototype: true, // 其他約束如有... }); fc.record(recordModel, { noNullPrototype: true, });與之配套的是字符串化輸出的精簡見下文高級用戶變化中的 serializer 一節(jié)null 原型對象現(xiàn)在序列化得更短。2. 統(tǒng)一的字符串構(gòu)建器4.0.0 將歷史上按字符集拆分的多個字符串 arbitrary 合并為單一的string通過unit約束指定字符來源。從 string.ts 的源碼可以確認(rèn)unit的完整取值范圍graphemeUnicode 標(biāo)準(zhǔn)定義的可打印字位grapheme可跨多個碼點依賴 Unicode 15 規(guī)范grapheme-composite限定為單個碼點的可打印字位grapheme-ascii可打印 ASCII 字符這也是unit的默認(rèn)值defaultValue grapheme-asciibinaryUnicode 全范圍內(nèi)0000-10FFFF的任意碼點不含半代理對binary-ascii0000-00FF 范圍內(nèi)任意 ASCII 碼點含控制字符或者傳入一個自定義的Arbitrarystring作為單元。值得注意發(fā)布說明明確提到團(tuán)隊把給字符串也強(qiáng)制更智能默認(rèn)值的計劃推遲到了 v5在 v4 中字符串默認(rèn)行為保持兼容后續(xù)會提供更多在 arbitrary 級別覆蓋默認(rèn)值的手段。3. 更精細(xì)的調(diào)度器fast-check 自 1.20.0 起提供檢測競態(tài)條件的調(diào)度器原語。v3 的實現(xiàn)存在兩個問題比預(yù)期更慢且允許在兩個已調(diào)度任務(wù)之間插入并執(zhí)行中間任務(wù)導(dǎo)致出現(xiàn)測試通過但新增微任務(wù)后失敗的不一致場景。v4 對調(diào)度器做了重寫Refactor: Rewrite ofscheduleSequence使任務(wù)只有在預(yù)期時刻確實存在時才會被調(diào)度行為更可預(yù)測。遷移指南中的示例清楚地展示了行為差異。設(shè)s為一個 scheduler 實例s.schedule(Promise.resolve(1)).then(async () { await something already resolved; s.schedule(Promise.resolve(2)); }); await s.waitAll();在 v3 中waitAll()結(jié)束時所有已調(diào)度任務(wù)包括Promise.resolve(2)都會被執(zhí)行而在 v4 中Promise.resolve(2)仍處于 pending 狀態(tài)——因為waitAll循環(huán)處理到await處就恢復(fù)了等待序列而第二個任務(wù)此時尚未被調(diào)度、對調(diào)度器而言仍是未知的。遷移指南還給出了對照如果示例中在調(diào)度第二個任務(wù)前多寫幾次awaitv3 的行為又會變回與 v4 一致即 v3 的行為取決于await數(shù)量本身就不一致v4 消除了這類邊緣場景下的意外。從當(dāng)前源碼看這一更精細(xì)的方向在 4.0.0 之后繼續(xù)演進(jìn)Scheduler.ts 接口 中waitOne/waitAll已被標(biāo)記deprecated分別推薦改用waitNext(1)與waitIdle()二者自 4.2.0 引入并保留waitFor(promise)用于等待某個特定任務(wù)。官方建議按場景選擇任務(wù)數(shù)已知用waitNext(n)等待所有已調(diào)度及可達(dá)任務(wù)全部落定用waitIdle()等待某個具體 Promise即使尚未調(diào)度用waitFor(promise)。破壞性變更全清單與遷移方法發(fā)布說明列出了自 3.23.2 以來的全部 20 項 Breaking Changes這里按主題歸類并給出源碼可驗證的替代方案。移除的字符串類 arbitraryascii*、hexa*、base64、stringOf、char16bits/string16bits、fullUnicode*、unicode*、char單字符 arbitrary 就是長度為 1 的字符串這是官方移除它們的核心理由。遷移指南from-3.x-to-4.x.md為每個被移除的 API 提供了可直接復(fù)用的重寫函數(shù)// ascii / asciiString function ascii(): fc.Arbitrarystring { return fc.string({ unit: binary-ascii, minLength: 1, maxLength: 1 }); } function asciiString(constraints: Omitfc.StringConstraints, unit {}): fc.Arbitrarystring { return fc.string({ ...constraints, unit: binary-ascii }); } // char function char(): fc.Arbitrarystring { return fc.string({ unit: grapheme-ascii, minLength: 1, maxLength: 1 }); } // hexa / hexaString function hexa(): fc.Arbitrarystring { const items 0123456789abcdef; return fc.integer({ min: 0, max: 15 }).map((n) items[n]); } function hexaString(constraints: Omitfc.StringConstraints, unit {}): fc.Arbitrarystring { return fc.string({ ...constraints, unit: hexa() }); } // fullUnicode / fullUnicodeString function fullUnicode(): fc.Arbitrarystring { return fc.string({ unit: binary, minLength: 1, maxLength: 1 }); } function fullUnicodeString(constraints: Omitfc.StringConstraints, unit {}): fc.Arbitrarystring { return fc.string({ ...constraints, unit: binary }); } // char16bits / string16bits function char16bits(): fc.Arbitrarystring { return fc.nat({ max: 0xffff }).map((n) String.fromCharCode(n)); } function string16bits(constraints: Omitfc.StringConstraints, unit {}): fc.Arbitrarystring { return fc.string({ ...constraints, unit: char16bits() }); }對于unicode/unicodeString僅限 BMP 的字符集遷移指南還特別提醒如果你當(dāng)初選unicode只是為了支持 Unicode很可能你真正需要的是fullUnicode全 Unicode 范圍。base64的替代是字符集枚舉fc.constantFrom展開 64 個字符帶可逆 unmapper 的進(jìn)階寫法見遷移指南的 Advanced rewriting 折疊塊。注意fc.base64String()被保留了——因為它表達(dá)的語義合法的 base64 編碼串超出了base64 字符的字符串。stringOf則直接改為fc.string({ unit: ... })-fc.stringOf(fc.constantFrom(Hello, World)); fc.string({ unit: fc.constantFrom(Hello, World) });uuid版本范圍擴(kuò)展到 v1–v8uuidV 被移除v3 的uuid只生成 v1–v5v4 擴(kuò)展默認(rèn)值到 v1–v8。從 uuid.ts 源碼確認(rèn)version缺省時取[1, 2, 3, 4, 5, 6, 7, 8]而約束類型允許 1–15 的單個版本或版本數(shù)組依據(jù) RFC 9562 的 version 字段定義。如果你的代碼只依賴 v1–v5可以顯式寫回-fc.uuid(); fc.uuid({ version: [1, 2, 3, 4, 5] });uuidV(n)自 3.21.0 起由uuid的version約束替代現(xiàn)已移除-fc.uuidV(4); fc.uuid({ version: 4 });.noBias / .noShrink 方法移除改用獨立 arbitrary這兩個方法自 3.20.0 起棄用v4 移除方法形式只保留同名獨立 arbitrary。從 noBias.ts 與 noShrink.ts 的實現(xiàn)可以看到兩者均為包裝器NoBiasArbitrary在generate時把 biasFactor 恒置為undefined禁用偏向NoShrinkArbitrary的shrink恒返回空迭代器且兩者都帶冪等檢查——重復(fù)包裹同一實例會直接返回原對象。-myArbitrary.noBias(); fc.noBias(myArbitrary); -myArbitrary.noShrink(); fc.noShrink(myArbitrary);big{U|}int{N|} 移除統(tǒng)一收斂到 fc.bigIntfc.bigIntN、fc.bigUintN、fc.bigUint被移除統(tǒng)一替換為fc.bigInt。需要時可自行重寫遷移指南給出的實現(xiàn)function bigIntN(n: number): fc.Arbitrarybigint { return fc.bigInt({ min: 1n BigInt(n - 1), max: (1n BigInt(n - 1)) - 1n }); } function bigUintN(n: number): fc.Arbitrarybigint { return fc.bigInt({ min: 0n, max: (1n BigInt(n)) - 1n }); } function bigUint(max: bigint (1n 256n) - 1n): fc.Arbitrarybigint { return fc.bigInt({ min: 0n, max }); }unicodeJson* 移除收斂到 json / jsonValueunicodeJson與unicodeJsonValue被json/jsonValue的stringUnit約束取代不再按字符集維護(hù)多套 API-fc.unicodeJson(); fc.json({ stringUnit: binary }); // 或 grapheme -fc.unicodeJsonValue(); fc.jsonValue({ stringUnit: binary }); // 或 graphemerecord 的 withDeletedKeys 徹底移除withDeletedKeys自 2.11.0 起被requiredKeys取代并標(biāo)記棄用v4 徹底移除fc.record(recordModel, { - withDeletedKeys: true, requiredKeys: [], }); fc.record(recordModel, { - withDeletedKeys: false, });Random.nextArrayInt 移除此項只影響手工實現(xiàn)Arbitrary接口的高級用戶。官方建議改用nextBigInt獲取大數(shù)值隨機(jī)量。Node ≥12.17.0 強(qiáng)制化對應(yīng) PR#5821構(gòu)建產(chǎn)物目標(biāo)從 ES2017 提升到 ES2020見下文工程化小節(jié)engines 聲明隨之收緊。新特性更好的類型推斷與類型簡化4.0.0 的 Features 部分包含四項類型層改進(jìn)最直觀的是constant/constantFrom的推斷方向反轉(zhuǎn)// v3 fc.constant(a); // Arbitrarystring fc.constanta(a); // Arbitrarya // v4 fc.constant(a); // Arbitrarya字面量自動推斷 fc.constantstring(a); // Arbitrarystring顯式指定才放寬constantFrom同理fc.constantFrom(a, b)現(xiàn)在直接推斷為Arbitrarya | b。另外兩項是ArbitraryXxxArray類型統(tǒng)一為ArbitraryXxxArrayArrayBuffer以及fc.record類型的簡化。錯誤報告新機(jī)制默認(rèn)使用 Error causev4 改用了標(biāo)準(zhǔn) Error Cause 機(jī)制當(dāng)謂詞拋出Error時fast-check 不再把失敗詳情拼進(jìn)新 Error 的 message而是把你的原始 Error 作為cause掛載上去便于測試運行器解析消息與堆棧。想恢復(fù)舊行為在 v4 中打開includeErrorInReport參數(shù)即可v3 中該開關(guān)叫errorWithCausev4 更名。這一點在源碼中可確認(rèn)Parameters.ts 定義了includeErrorInReport?: booleanRunDetailsFormatter.ts 根據(jù)該標(biāo)志決定 message 是否拼接原始錯誤Runner.spec.ts 中有對應(yīng)的行為測試。工程化與性能改進(jìn)發(fā)布說明的 Fixes 部分包含大量工程項可歸納為幾條主線構(gòu)建鏈遷移到 ESM產(chǎn)物目標(biāo) ES2020。當(dāng)前倉庫中構(gòu)建統(tǒng)一走 rolldownrolldown.common.config.js主產(chǎn)物為format: esm且配置了treeshake: { moduleSideEffects: false }package.json 中同樣聲明sideEffects: false。這正是 changelog 中 Mark all arbitraries as side-effect free 兩項落地的形態(tài)使打包器可以對 fast-check 做更徹底的 tree-shaking。依賴管理從 yarn 切換到 pnpm倉庫根目錄可見pnpm-workspace.yaml與pnpm-lock.yamlCI 命令切換到node --run、CI 作業(yè)遷移到 Node 22。一系列生成路徑上的性能優(yōu)化property::run采用嚴(yán)格相等判斷加速、無 cause 時延遲計算 Error stack、scheduleSequence調(diào)度加速、競態(tài)調(diào)度器提速、double重寫提速、ipV6使用緩存字符串構(gòu)建器、runner 參數(shù)與object約束讀取提速等。關(guān)鍵 bug 修復(fù)scheduleSequence的拒絕rejection處理更完善json對外部原型污染poisoning具備抵抗力倉庫中還有配套的 packages/poisoning 檢測包與mixedCase中冗余 BigInt 檢查的移除。面向高級用戶的破壞性變更遷移指南的 Advanced usages 一節(jié)面向自定義 reporter、自定義Arbitrary/runner 的實現(xiàn)者包含四項需要留意的變化RunDetails 移除error字段fc.check返回結(jié)果中不再提供error字符串字段請改用 v3.0.0 引入的errorInstance。這與上文 Error cause 機(jī)制配套延遲計算 Error stack 也帶來相應(yīng)收益。IRawProperty執(zhí)行器必須顯式調(diào)用runBeforeEach/runAfterEach自定義屬性 runner自實現(xiàn)的fc.assert/fc.check替代物需要顯式驅(qū)動這兩個鉤子v3 中可以通過 run 方法的第二個參數(shù)傳true提前適配。序列化器輸出變更null 原型對象的 stringify 結(jié)果從Object.create(null)/Object.assign(Object.create(null),{a:1})改為更短的{__proto__:null}/{__proto__:null,a:1}。從 stringify.ts 可見其實現(xiàn)Object.getPrototypeOf(value) null時插入__proto__:null鍵且 stringify.spec.ts 中固化了這些快照斷言。依賴自定義上報/序列化格式的用戶需要留意。CommandWrapper / CommandsIterable 的 Symbol 方法不再出現(xiàn)在類型聲明中toStringMethod、asyncToStringMethod、cloneMethod這些符號方法在運行時依然存在但 TypeScript 類型中不再暴露對應(yīng) CI 層面的isolatedDeclarations啟用。升級行動清單結(jié)合發(fā)布說明與遷移指南從 v3 到 v4 的實操步驟可以濃縮為先升級至最新 3.x逐項搜索代碼中的棄用項ascii/asciiString、hexa/hexaString、base64、stringOf、char16bits/string16bits、fullUnicode/fullUnicodeString、unicode/unicodeString、char、uuidV、unicodeJson/unicodeJsonValue、bigIntN/bigUintN/bigUint、.noBias()、.noShrink()、withDeletedKeys按遷移指南給出的重寫函數(shù)逐一替換評估默認(rèn)行為反轉(zhuǎn)確認(rèn)fc.date()Invalid Date、fc.record/fc.dictionary/fc.objectnull 原型、fc.uuid()v6–v8的新默認(rèn)值是否可接受不能接受的地方顯式加回noInvalidDate: true、noNullPrototype: true、version: [1, 2, 3, 4, 5]切換錯誤上報習(xí)慣默認(rèn)改為 Error cause 掛載需要舊式拼接消息時打開includeErrorInReport檢查環(huán)境基線Node ≥12.17.0、ES2020、TypeScript ≥5.0自定義實現(xiàn)者自查RunDetails.error字段、IRawProperty鉤子調(diào)用、Command 相關(guān)的 Symbol 類型引用。完成以上步驟后遷移指南的結(jié)論是切換到 v4 應(yīng)當(dāng)是直接的should be straightforward因為剩余的變更要么是非破壞的增強(qiáng)類型推斷、性能要么是面向高級使用場景的行為收緊調(diào)度器更精確、序列化更短。贊分享開發(fā)工具測試【免費下載鏈接】fast-checkProperty based testing framework for JavaScript (like QuickCheck) written in TypeScript項目地址https://gitcode.com/gh_mirrors/fa/fast-check點擊查看免費下載相關(guān)推薦CoffeeScript 0.5.5 發(fā)布解析字符串插值語法與命令行默認(rèn)行為變更指南CoffeeScript 0.5.5 發(fā)布解析字符串插值語法與命令行默認(rèn)行為變更指南 本篇文章圍繞 CoffeeScript 0.5.5發(fā)布于 2010 0編程語言編譯器抖音去水印批量下載免費工具博主200條作品20分鐘下完抖音去水印批量下載免費工具博主200條作品20分鐘下完 上周三做競品復(fù)盤老板甩給我一個博主主頁鏈接讓我把他發(fā)的都存下來。換以前我得一整下午對著網(wǎng)頁復(fù)制網(wǎng)頁爬蟲CLIfast-check 3.9.0 發(fā)布解讀細(xì)粒度 act 讓競態(tài)條件檢測更精準(zhǔn)fast check 3.9.0 發(fā)布解讀細(xì)粒度 act 讓競態(tài)條件檢測更精準(zhǔn) 本篇技術(shù)指南圍繞 fast check 3.9.0 版本的核心更新展開它把調(diào)開發(fā)工具測試上一篇預(yù)約發(fā)送不遲到Simple SMS Messenger 定時消息功能使用教程下一篇終極指南如何用F_Record插件一鍵錄制Photoshop繪畫全過程創(chuàng)作聲明:本文部分內(nèi)容由AI輔助生成(AIGC),僅供參考