有没有办法用 Jest 顺序运行一些测试?

Posted

技术标签:

【中文标题】有没有办法用 Jest 顺序运行一些测试?【英文标题】:Is there a way to run some tests sequentially with Jest? 【发布时间】:2018-04-27 17:17:52 【问题描述】:

Jest 默认情况下并行运行您的测试套件,但有一个标志 (--runInBand) 允许您按顺序运行整个套件(如 here 指出的那样)

我有一些无法并行运行的测试,但按顺序运行整个套件总共需要更长的时间,所以我的问题是是否有办法只以这种方式运行 some 测试(例如为这些测试设置标志或类似的东西)。

【问题讨论】:

“我有一些测试不能并行运行” - 这通常暗示测试不是独立的,一个更大的问题......或者你正在做的不是' t 并且不应该是单元测试。 是的,我正在为 pact.js 启动一个外部服务,这并不是那么容易改变的。对我来说,一个可以接受的折衷方案是,如果我可以隔离这些测试并让它们按顺序运行而不损失整个套件的速度 【参考方案1】:

我也需要相同的功能。我有大量想要运行的 Jest 集成测试套件。但是,由于需要设置和拆除共享资源,有些不能并行运行。所以,这是我想出的解决方案。

我从以下位置更新了我的 package.json 脚本:


  ...
  "scripts": 
    ...
    "test": "npm run test:unit && npm run test:integration",
    "test:integration": "jest --config=__tests__/integration/jest.config.js",
    "test:unit": "jest --config=__tests__/unit/jest.config.js"
  ,
  ...


  ...
  "scripts": 
    ...
    "test": "npm run test:unit && npm run test:integration",
    "test:integration": "npm run test:integration:sequential && npm run test:integration:parallel",
    "test:integration:parallel": "jest --config=__tests__/integration/jest.config.js",
    "test:integration:sequential": "jest --config=__tests__/integration/jest.config.js --runInBand",
    "test:unit": "jest --config=__tests__/unit/jest.config.js"
  ,
  ...

然后我从

更新了__tests__/integration/jest.config.js
module.exports = 
  // Note: rootDir is relative to the directory containing this file.
  rootDir: './src',
  setupFiles: [
    '../setup.js',
  ],
  testPathIgnorePatterns: [
    ...
  ],
;

const Path = require('path');

const  defaults  = require('jest-config');
const klawSync = require('klaw-sync')
const mm = require('micromatch');

// Note: rootDir is relative to the directory containing this file.
const rootDir = './src';
const  testMatch  = defaults;

// TODO: Add the paths to the test suites that need to be run
// sequentially to this array.
const sequentialTestPathMatchPatterns = [
  '<rootDir>/TestSuite1ToRunSequentially.spec.js',
  '<rootDir>/TestSuite2ToRunSequentially.spec.js',
  ...
];

const parallelTestPathIgnorePatterns = [
  ...
];

let testPathIgnorePatterns = [
  ...parallelTestPathIgnorePatterns,
  ...sequentialTestPathMatchPatterns,
];

const sequential = process.argv.includes('--runInBand');
if (sequential) 
  const absRootDir = Path.resolve(__dirname, rootDir);
  let filenames = klawSync(absRootDir,  nodir: true )
    .map(file => file.path)
    .map(file => file.replace(absRootDir, ''))
    .map(file => file.replace(/\\/g, '/'))
    .map(file => '<rootDir>' + file);
  filenames = mm(filenames, testMatch);
  testPathIgnorePatterns = mm.not(filenames, sequentialTestPathMatchPatterns);


module.exports = 
  rootDir,
  setupFiles: [
    '../setup.js',
  ],
  testMatch,
  testPathIgnorePatterns,
;

更新后的jest.config.js 依赖于jest-configklaw-syncmicromatch

npm install --save-dev jest-config klaw-sync micromatch

现在,如果您只想运行需要按顺序运行的测试,则可以运行 npm run test:integration:sequential

或运行npm run test:integration:parallel 进行并行测试。

或运行npm run test:integration 以首先运行顺序测试。完成后,将运行并行测试。

或者运行npm run test 来运行单元测试和集成测试。

注意:我在单元测试和集成测试中使用的目录结构如下:

__tests__
  integration
    src
      *.spec.js
      *.test.js
    jest.config.js
  unit
    src
      *.spec.js
      *.test.js
    jest.config.js

【讨论】:

这么简单的事情太麻烦了,Jest 确实缺乏非常重要的功能来标记要按顺序运行的描述块。 最后,如果第一个没有失败,它将依次运行两个套件。这是想要的吗? 在开玩笑的辩护中 - 使用工作池运行测试是明智之举。在我们的辩护中 - 在每次测试之前/之后清除数据库也是一件明智的事情,两者完全不一致。感谢您提供有关--runInBand 标志的提示!绝对救了我。在每次测试之前我开始进行适当的清理之后,我的所有测试都开始失败。【参考方案2】:

使用串行测试运行器:

npm install jest-serial-runner --save-dev

设置 jest 以使用它,例如在 jest.config.js 中:

module.exports = 
   ...,
   runner: 'jest-serial-runner'
;

您可以使用项目功能将其仅应用于一部分测试。见https://jestjs.io/docs/en/configuration#projects-arraystring--projectconfig

【讨论】:

致投反对票的人:如果您评论了您认为错误或可以改进的地方,对每个人都会更有帮助。【参考方案3】:

扩展自Joachim Lous的答案,您可以将测试文件划分为项目,并为每个项目指定不同的运行器。

jest.config.js:

module.exports = 
  projects: [
    
      displayName: "default-tests",
      testEnvironment: "node",
    ,
    
      displayName: "serial-tests",
      testEnvironment: "node",
      runner: "jest-serial-runner",
      testMatch: ["**/?(*.)+(serial-test).[jt]s?(x)"],
    ,
  ],

然后,将需要按顺序运行的所有测试重命名为 *.serial-test.js(而不是 *.test.js)。

【讨论】:

【参考方案4】:

这有点提升,但我认为值得发布我的最终配置。我遇到了同样的问题,我扩展了Joachim Lous' 和Fishball's 的答案以获得令人满意的结果。这是我的最终设置:

我的项目的缩写目录列表:

├── src
│   ├── index.ts
│   ├── Io.ts
│   ├── Modules
│   │   └── index.ts
│   └── .....
└── tests
    ├── EndToEnd
    │   ├── Fixtures.ts
    │   ├── Mq.spec.ts
    │   ├── LegalEntities.spec.ts
    │   └── Utils.ts
    └── UnitTests
        ├── LegalEntities.spec.ts
        ├── Assets.spec.ts
        └── Utils.ts

我的(缩写)package.json 文件,其中包含我的笑话配置:


  "name": "my-project",
  "scripts": 
    "build": "scripts/build",
    "check": "tsc --noEmit",
    "test": "jest"
  ,
  "....": "....",
  "jest": 
    "projects": [
      
        "displayName": "unit-tests",
        "testEnvironment": "node",
        "verbose": true,
        "testMatch": [
          "<rootDir>/tests/**/*.spec.ts",
          "!**/EndToEnd/**/*.spec.ts"
        ],
        "transform": 
          "^.+\\.tsx?$": "ts-jest"
        
      ,
      
        "displayName": "e2e-tests",
        "testEnvironment": "node",
        "verbose": true,
        "maxWorkers": 1,
        "testMatch": [
          "<rootDir>/tests/EndToEnd/**/*.spec.ts"   
        ],
        "transform": 
          "^.+\\.tsx?$": "ts-jest"
        
      
    ]
  

注意事项:

当开玩笑地使用projects 键时,我不得不将 all 配置移动到各个项目块中。使用项目配置与使用全局配置是互斥的。 我没有使用其他答案中提到的 runner 指令。相反,我使用 maxWorkers 选项将执行限制为 1 个工作程序(即,本质上是串行的)。这意味着我不必使用更多的依赖项。 由于某种原因,否定语法对我的单元测试很挑剔。我想将单元测试指定为所有不在 EndToEnd 目录中的测试,我花了一些时间试图开玩笑地正确地做到这一点。

感谢其他所有人提供可行的起点。希望这对其他人有帮助!

【讨论】:

有趣的是,这个设置不应该工作(而且不适合我)。请参阅此问题:github.com/facebook/jest/issues/10936 maxWorkers 在项目级别被忽略。

以上是关于有没有办法用 Jest 顺序运行一些测试?的主要内容,如果未能解决你的问题,请参考以下文章

有没有办法使用 MSTests 顺序运行单元测试?

有没有办法在 Create React App 应用程序中按顺序运行笑话测试?

为啥 Jest --runInBand 会加快测试速度?

有没有办法以所需的顺序运行Specflow场景(C#Selenium)?

beforeEach 和 beforeAll 以啥顺序执行?

按特定顺序运行 PHPUnit 测试