Jest如何有序地執行測試

2023-01-19 21:00:35

專案場景:

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上看到了相同的訴求,並且有人給出了正確的解答。那叫一個後悔啊,我怎麼沒早點看到