專案場景:
node環境下編寫js庫,處於規範性考慮,需要做單元測試,我選擇了Jest
問題描述
我的js庫需要訪問資料庫,因此操作都是非同步的,而且各個測試單元有嚴格的先後執行順序(比如,建表 > 插 > 改 > 刪),而Jest的每個單元是獨立的,並且預設下並行執行測試。
為此,我查詢瞭解決方案,官方手冊和一些博文帖子都告訴我,在jest配置檔案中(jest.config.js),設定testSequencer屬性,對應的是一個自定義的js模組,它匯出了一個按照路徑字母的排序演算法,如下:
官方手冊給出的custom-sequencer.js
const Sequencer = require('@jest/test-sequencer').default;
class CustomSequencer extends Sequencer {
sort(tests) {
// Test structure information
// https://github.com/facebook/jest/blob/6b8b1404a1d9254e7d5d90a8934087a9c9899dab/packages/jest-runner/src/types.ts#L17-L21
const copyTests = Array.from(tests);
return copyTests.sort((testA, testB) => (testA.path > testB.path ? 1 : -1));
}
}
module.exports = CustomSequencer;
相應的jest.config.js配置
/** @type {import('jest').Config} */
const config = {
testSequencer: 'path/to/custom-sequencer.js',
};
module. Exports = config;
我照做了,但我的單元依然隨機地並行執行,或只是最初載入時在表面上排好了隊,即便我設定maxConcurrency為1(A number limiting the number of tests that are allowed to run at the same time when using test.concurrent. Any test above this limit will be queued and executed once a slot is released.)。在有一些帖子的回答中,有人則認為,Jest難以支援指定順序,或者要額外寫不少程式碼才能實現Jest有序測試。
解決方案:
僅僅為jest指定排序演算法是不夠的,因為預設執行模式就是並行執行!
同時,應該將jest設定為序列執行,這樣測試單元才會按照預期的順序執行
你可以在執行時加上runInBand引數:npm test -- --runInBand
可以看到,對於我的四個測試檔案,.1.dbIns.tes.js等等,從1-4執行了
你也可以在package.json中為npm指令碼新增這個引數:
"scripts": {
"test": "jest",
"test-inline": "jest \"--runInBand\"", //注意是 "--runInBand" 而不是 -- --runInBand,而且一定要轉義雙引號
"babel-build": "babel lib/sql.js -d dist"
},
或者在package.json中,設定maxWorkers為1:
( 官方手冊:Specifies the maximum number of workers the worker-pool will spawn for running tests. In single run mode, this defaults to the number of the cores available on your machine minus one for the main thread)
簡而言之,你可以認為maxWorkers=1時Jest為單執行緒
const config = {
reporters: [~
"default",
"jest-allure"
],
setupFilesAfterEnv: ["jest-allure/dist/setup"],
testRunner: "jest-jasmine2",
testSequencer: './jest.sequencer.js',
maxWorkers: 1,
};
module.exports = config;
官方給出的排序法,是按檔案路徑字母排的序,我個人不喜歡用a,b,aa,ab為檔案當作字首,看著很難受,沒有數字來的直觀,如果你和我一樣,可以使用我改寫的排序模組:
此外,你的測試檔案需要按照上圖我那樣子命名:.1.xxx.test.js
const Sequencer = require('@jest/test-sequencer').default;
class CustomSequencer extends Sequencer {
/**
* Sort test to determine order of execution
* Sorting is applied after sharding
*/
sort(tests) {
// Test structure information
// https://github.com/facebook/jest/blob/6b8b1404a1d9254e7d5d90a8934087a9c9899dab/packages/jest-runner/src/types.ts#L17-L21
const copyTests = Array.from(tests);
return copyTests.sort((testA, testB) => (parseInt(testA.path.split('.').reverse()[3]) > parseInt(testB.path.split('.').reverse()[3]) ? 1 : -1));
}
}
module.exports = CustomSequencer;
題外話
寫完這篇文後,我在stackoverflow上看到了相同的訴求,並且有人給出了正確的解答。那叫一個後悔啊,我怎麼沒早點看到