使用TypeScript改造構建工具及測試用例
最近的一段時間一直在搞TypeScript
,一個巨硬出品、賦予JavaScript
語言靜態型別和編譯的語言。
第一個完全使用TypeScript
重構的純Node.js
專案已經上線並穩定執行了。
第二個前後端的專案目前也在重構中,關於前端基於webpack
的TypeScript
套路之前也有提到過:TypeScript在react專案中的實踐。
但是這些做完以後也總感覺缺了點兒什麼 (沒有盡興):
是的,依然有五分之一的JavaScript
程式碼存在於專案中,作為一個TypeScript
的示例專案,表現的很不純粹。
所以有沒有可能將這些JavaScript
程式碼也換成TypeScript
呢?
答案肯定是有的,首先需要分析這些程式碼都是什麼:
-
Webpack
打包時的配置檔案 - 一些簡單的測試用例(使用的mocha和chai)
知道了是哪些地方還在使用JavaScript
,這件事兒就變得很好解決了,從構建工具(Webpack
)開始,逐個擊破,將這些全部替換為TypeScript
。
Webpack 的 TypeScript 實現版本
在這8102
年,很幸福,Webpack
官方已經支援了TypeScript
編寫配置檔案,文件地址。
除了TypeScript
以外還支援JSX
和CoffeeScript
的直譯器,在這就忽略它們的存在了
依賴的安裝
首先是要安裝TypeScript
相關的一套各種依賴,包括直譯器及該語言的核心模組:
npm install -D typescript ts-node
typescript
為這個語言的核心模組,ts-node
用於直接執行.ts
檔案,而不需要像tsc
那樣會編譯輸出.js
檔案。
ts-node helloworld.ts
因為要在TypeScript
環境下使用Webpack
相關的東東,所以要安裝對應的types
。
也就是Webpack
所對應的那些*.d.ts
,用來告訴TypeScript
這是個什麼物件,提供什麼方法。
npm i -D @types/webpack
一些常用的pLugin
都會有對應的@types
檔案,可以簡單的通過npm info @types/XXX
來檢查是否存在
如果是一些小眾的plugin
,則可能需要自己建立對應的d.ts
檔案,例如我們一直在用的qiniu-webpack-plugin
,這個就沒有對應的@types
包的,所以就自己建立一個空檔案來告訴TypeScript
這是個啥:
declare module `qiniu-webpack-plugin` // 就一個簡單的定義即可
// 如果還有其他的包,直接放到同一個檔案就行了
// 檔名也沒有要求,保證是 d.ts 結尾即可
放置的位置沒有什麼限制,隨便丟,一般建議放到types
資料夾下
最後就是.ts
檔案在執行時的一些配置檔案設定。
用來執行Webpack
的.ts
檔案對tsconfig.json
有一些小小的要求。compilerOptions
下的target
選項必須是es5
,這個代表著輸出的格式。
以及module
要求選擇commonjs
。
{
"compilerOptions": {
"module": "commonjs",
"target": "es5",
"esModuleInterop": true
}
}
但一般來講,執行Webpack
的同級目錄都已經存在了tsconfig.json
,用於實際的前端程式碼編譯,很可能兩個配置檔案的引數並不一樣。
如果因為要使用Webpack
去修改真正的程式碼配置引數肯定是不可取的。
所以我們就會用到這麼一個包,用來改變ts-node
執行時所依賴的配置檔案:tsconfig-paths
在Readme
中發現了這樣的說法:If process.env.TS_NODE_PROJECT is set it will be used to resolved tsconfig.json
。
在Webpack
的文件中同樣也提到了這句,所以這是一個相容的方法,在命令執行時指定一個路徑,在不影響原有配置的情況下建立一個供Webpack
打包時使用的配置。
- 將上述的配置檔案改名為其它名稱,
Webpack
文件示例中為tsconfig-for-webpack-config.json
,這裡就直接沿用了 - 然後新增
npm script
如下
{
"scripts": {
"build": "TS_NODE_PROJECT=tsconfig-for-webpack-config.json webpack --config configs.ts"
}
}
檔案的編寫
關於配置檔案,從JavaScript
切換到TypeScript
實際上並不會有太大的改動,因為Webpack
的配置檔案大多都是寫死的文字/常量。
很多型別都是自動生成的,基本可以不用手動指定,一個簡單的示例:
import { Configuration } from `webpack`
const config: Configuration = {
mode: process.env.NODE_ENV === `production` ? `production` : `development`,
}
export default config
Configuration
是一個Webpack
定義的介面(interface
),用來規範一個物件的行為。
在VS Code
下按住Command
+ 單擊可以直接跳轉到具體的webpack.d.ts
定義檔案那裡,可以看到詳細的定義資訊。
各種常用的規則都寫在了這裡,使用TypeScript
的一個好處就是,當要實現一個功能時你不再需要去網站上查詢應該要配置什麼,可以直接翻看d.ts
的定義。
如果註釋寫得足夠完善,基本可以當成文件來用了,而且在VS Code
編輯器中還有動態的提示,以及一些錯誤的糾正,比如上述的NODE_ENV
的獲取,如果直接寫process.env.NODE_ENV || `development`
是會丟擲一個異常的,因為從d.ts
中可以看到,關於mode
只有三個有效值production
、developemnt
和none
,而process.env.NODE_ENV
顯然只是一個字串型別的變數。
所以我們需要使用三元運算子保證傳入的引數一定是我們想要的。
以及在編寫的過程中,如果有一些自定義的plugin
之類的,可能在使用的過程中會拋異常提示說某個物件不是有效的Plugin
物件,一個很簡單的方法,在對應的plugin
後邊新增一個as webpack.Plugin
即可。
在這裡TypeScript
所做的只是靜態的檢查,並不會對實際的程式碼執行造成任何影響,就算型別因為強行as
而改變,也只是編譯期的修改,在實際執行的JavaScript
程式碼中還是弱型別的
在完成了上述的操作後,再執行npm run XXX
就可以直接執行TypeScript
版本的Webpack
配置咯。
探索期間的一件趣事
因為我的專案根目錄已經安裝了ts-node
,而前端專案是作為其中的一個資料夾存在的,所以就沒有再次進行安裝。
這就帶來了一個令人吐血的問題。
首先全部流程走完以後,我直接在命令列中輸入TS_NODE_PROJECT=XXX.json NODE_ENV=dev webpack --config ./webpack/dev.ts
完美執行,然後將這行命令放到了npm scripts
中:
{
"scripts": {
"start": "TS_NODE_PROJECT=XXX.json NODE_ENV=dev webpack --config ./webpack/dev.ts"
}
}
再次執行npm start
,發現竟然出錯了-.-,提示我說import
語法不能被識別,這個很顯然就是沒有應用我們在ts_NODE_PROJECT
中指定的config
檔案。
剛開始並不知道問題出在哪,因為這個在命令列中直接執行並沒有任何問題。
期間曾經懷疑是否是環境變數沒有被正確設定,還使用了cross-env
這個外掛,甚至將命令寫到了一個sh
檔案中進行執行。
然而問題依然存在,後來在一個群中跟小夥伴們聊起了這個問題,有人提出,你是不是全域性安裝了ts-node
。
檢查以後發現,果然是的,在命令列執行時使用的是全域性的ts-node
,但是在npm scripts
中使用的是本地的ts-node
。
在命令列環境執行時還以為是會自動尋找父資料夾node_modules
下邊的依賴,其實是使用的全域性包。
乖乖的在client-src
資料夾下也安裝了ts-node
就解決了這個問題。
全域性依賴害人。。
測試用例的改造
前邊的Webpack
改為TypeScript
大多數原因是因為強迫症所致。
但是測試用例的TypeScript
改造則是一個能極大提高效率的操作。
為什麼要在測試用例中使用 TypeScript
測試用例使用chai
來編寫,(之前的Postman
也是用的chai
的語法)chai
提供了一系列的語義化鏈式呼叫來實現斷言。
在之前的分享中也提到過,這麼多的命令你並不需要完全記住,只知道一個expect(XXX).to.equal(true)
就夠了。
但是這樣的通篇to.equal(true)
是巨醜無比的,而如果使用那些語義化的鏈式呼叫,在不熟練的情況下很容易就會得到:
Error: XXX.XXX is not a function
因為這確實有一個門檻問題,必須要寫很多才能記住呼叫規則,各種not
、includes
的操作。
但是接入了TypeScript
以後,這些問題都迎刃而解了。
也是前邊提到的,所有的TypeScript
模組都有其對應的.d.ts
檔案,用來告訴我們這個模組是做什麼的,提供了什麼可以使用。
也就是說在測試用例編寫時,我們可以通過動態提示來快速的書寫斷言,而不需要結合著文件去進行“翻譯”。
使用方式
如果是之前有寫過mocha
和chai
的童鞋,基本上修改檔案字尾+安裝對應的@types
即可。
可以直接跳到這裡來:開始編寫測試指令碼
但是如果對測試用例感興趣,但是並沒有使用過的童鞋,可以看下邊的一個基本步驟。
安裝依賴
-
TypeScript
相關的安裝,npm i -D typescript ts-node
-
Mocha
、chai
相關的安裝,npm i -D mocha chai @types/mocha @types/chai
- 如果需要涉及到一些API的請求,可以額外安裝
chai-http
,npm i -D chai-http @types/chai-http
環境的依賴就已經完成了,如果額外的使用一些其他的外掛,記得安裝對應的@types
檔案即可。
如果有使用ESLint之類的外掛,可能會提示modules
必須存在於dependencies
而非devDependencies
這是ESLint的import/no-extraneous-dependencies
規則導致的,針對這個,我們目前的方案是新增一些例外:
import/no-extraneous-dependencies:
- 2
- devDependencies:
- "**/*.test.js"
- "**/*.spec.js"
- "**/webpack*"
- "**/webpack/*"
針對這些目錄下的檔案/資料夾不進行校驗。是的,webpack的使用也會遇到這個問題
開始編寫測試指令碼
如果是對原有的測試指令碼進行修改,無外乎修改字尾、新增一些必要的型別宣告,不會對邏輯造成任何修改。
一個簡單的示例
// number-comma.ts
export default (num: number | string) => String(num).replace(/B(?=(d{3})+$)/g, `,`)
// number-comma.spec.ts
import chai from `chai`
import numberComma from `./number-comma`
const { expect } = chai
// 測試項
describe(`number-comma`, () => {
// 子專案1
it(``1234567` should transform to `1,234,567``, done => {
expect(numberComma(1234567)).to.equal(`1,234,567`)
done()
})
// 子專案2
it(``123` should never transform`, done => {
const num = 123
expect(numberComma(num)).to.equal(String(num))
done()
})
})
如果全域性沒有安裝mocha
,記得將命令寫到npm script
中,或者通過下述方式執行
./node_modules/mocha/bin/mocha -r ts-node/register test/number-comma.spec.ts
# 如果直接這樣寫,會丟擲異常提示 mocha 不是命令
mocha -r ts-node/register test/number-comma.spec.ts
mocha
有一點兒比較好的是提供了-r
命令來讓你手動指定執行測試用例指令碼所使用的直譯器,這裡直接設定為ts-node
的路徑ts-node/register
,然後就可以在後邊直接跟一個檔名(或者是一些萬用字元)。
目前我們在專案中批量執行測試用例的命令如下:
{
"scripts": {
"test": "mocha -r ts-node/register test/**/*.spec.ts"
}
}
npm test
可以直接呼叫,而不需要新增run
命令符,類似的還有start
、build
等等
一鍵執行以後就可以得到我們想要的結果了,再也不用擔心一些程式碼的改動會影響到其他模組的邏輯了 (前提是認真寫測試用例)
小結
做完上邊兩步的操作以後,我們的專案就實現了100%的TypeScript
化,在任何地方享受靜態編譯語法所帶來的好處。
附上更新後的程式碼含量截圖:
最近針對TypeScript
做了很多事情,從Node.js
、React
以及這次的Webpack
與Mocha+Chai
。TypeScript
因為其存在一個編譯的過程,極大的降低了程式碼出bug的可能性,提高程式的穩定度。
全面切換到TypeScript
更是能夠降低在兩種語法之間互相切換時所帶來的不必要的消耗,祝大家搬磚愉快。
之前關於 TypeScript 的筆記
一個完整的 TypeScript 示例
歡迎各位來討論關於TypeScript
使用上的一些問題,針對穩重的感覺不足之處也歡迎指出。
參考資料
相關文章
- 萬能測試用例及測試用例編寫方法(待更新)
- TestLink測試用例管理工具使用說明
- 使用Angular與TypeScript構建Electron應用(六)AngularTypeScript
- 探索性測試及基本用例
- 測試面試-測試用例面試
- 測試用例
- 測試——水杯的測試用例
- 測試用例和測試方法
- 測試用例—教室
- 【5】測試用例
- C# 使用SpecFlow建立BDD測試用例C#
- 使用 Xunit.DependencyInjection 改造測試專案
- 基於LangChain手工測試用例轉App自動化測試生成工具LangChainAPP
- 基於LangChain手工測試用例轉Web自動化測試生成工具LangChainWeb
- 基於LangChain手工測試用例轉介面自動化測試生成工具LangChain
- 自動化測試|Eolink Apikit 如何儲存、使用測試用例API
- 手工測試用例與自動化測試用例的區別
- 2024年測試用例管理9大最佳工具(包括免費、付費及開源)
- HTML5遊戲開發(三):使用webpack構建TypeScript應用HTML遊戲開發WebTypeScript
- postman寫測試用例Postman
- 測試用例的方法
- 黑盒測試用例二
- 面經-測試用例
- 【黑盒測試】測試用例的常用方法
- 黑盒測試用例設計方法使用場合
- 大型專案裡Flutter測試應用例項整合測試深度使用Flutter
- Pytest測試框架(一):pytest安裝及用例執行框架
- 如何寫好測試用例以及go單元測試工具testify簡單介紹Go
- 程式碼測試用例指南
- 測試用例最佳實踐
- 測試用例設計指南
- 怎樣寫測試用例?
- 測試用例編寫方法
- httprunner 4.x學習 - 12 測試用例引用另一個測試用例HTTP
- 測試工具-XPath使用
- python TestCase測試用例怎麼用Python
- 【功能測試】兩部電梯的測試用例
- APP測試設計測試用例的要點APP