Jest - 简单的测试很慢

157

我正在使用Jest测试一个Angular应用程序,简单的测试运行时间非常长,但我似乎无法弄清楚为什么。

package.json 中我的 Jest 设置:

"jest": {
  "modulePaths": [
    "<rootDir>/src",
    "<rootDir>/node_modules"
  ],
  "testPathIgnorePatterns": [
    ".git/.*",
    "node_modules/.*"
  ],
  "transformIgnorePatterns": [
    "node_modules/.*",
    ".*\\.js"
  ],
  "setupTestFrameworkScriptFile": "<rootDir>/src/setupJest.js",
  "preset": "jest-preset-angular",
  "testEnvironment": "jsdom",
  "testRegex": "src/app/.*\\.spec\\.ts$",
  "moduleFileExtensions": [
    "ts",
    "js",
    "json"
  ],
  "verbose": true,
  "cacheDirectory": ".jest-cache",
  "coveragePathIgnorePatterns": [
    ".*\\.(shim\\.ngstyle|ngfactory)\\.ts"
  ],
  "globals": {
    "ts-jest": {
      "tsConfigFile": "./tsconfig.json"
    },
    "__TRANSFORM_HTML__": true
  }
}

我的 Jest 设置文件:

'use strict';
require('core-js/es6/reflect');
require('core-js/es7/reflect');
require('zone.js');
require('zone.js/dist/proxy.js');
require('zone.js/dist/sync-test');
require('zone.js/dist/async-test');
require('zone.js/dist/fake-async-test');
require('jest-zone-patch');

const getTestBed = require('@angular/core/testing').getTestBed;
const BrowserDynamicTestingModule = require('@angular/platform-browser-dynamic/testing').BrowserDynamicTestingModule;
const platformBrowserDynamicTesting = require('@angular/platform-browser-dynamic/testing')  .platformBrowserDynamicTesting;

getTestBed().initTestEnvironment(
    BrowserDynamicTestingModule,
    platformBrowserDynamicTesting()
);

这是我的简单测试:

fdescribe('RichTextEditorComponent', () => {
  it('should be fast', () => {
    expect(true).toBeTruthy();
  });
});

有没有人知道为什么这需要9秒以上?在此输入图片描述


1
使用 Windows 7 - 64 位 / node 6.9.4 / npm 3.10.10。 - Tucker
2
@RClemens 是的 - 这与jest本身的包在Windows机器上运行较慢有关 - 如果我没记错的话。 - Tucker
1
可能与这个问题这个问题相关。如果你正在使用监视模式,禁用它可以节省几秒钟的时间。显然,在某些虚拟机上按顺序运行测试可以提高50%的性能。您也可以尝试通过添加--runInBand标志来实现这一点。 - Antoine Boisier-Michaud
2
我能找到的唯一与配置相关的原因是您正在使用 setupTestFrameworkScriptFile,它在每个测试运行之前运行。您应该使用 setupFiles 设置,它是一个字符串数组。其中一个字符串应该指向您的文件,并且它将为每个规范文件运行,而不是为每个测试运行。https://jestjs.io/docs/en/configuration#setupfiles-array - fnune
1
WSL2 用户: 除了将 jest 安装为开发依赖项之外,还需全局安装它,并在 package.json 文件中使用其二进制文件的绝对路径,例如:"test": "/usr/bin/jest", - aderchox
显示剩余5条评论
15个回答

148

另一个可能性是ts-jest速度慢。有关此问题的问题并未完全解决。

讨论了各种解决方法。它们包括isolatedModules=true设置为true以及使用--maxWorkers=1。也就是说,在jest.config.js文件中。

'use strict';

module.exports = {
    preset: 'ts-jest',
    testEnvironment: 'node',
    globals: {
        'ts-jest': {
            isolatedModules: true
        }
    },
}

并运行

yarn test --maxWorkers=1

或许值得一试。另外,也有可能放弃使用ts-jest,转而使用babel进行转译。


8
在Linux机器上执行测试速度缓慢。 isolatedModules 是关键。没有设置 maxWorkers=1 - erjitka
9
请注意,“isolatedModules: true”会禁用类型检查。 - Maxim Mazurok
2
@MaximMazurok 来源 - ynn
5
ts-jest 29 开始,在 globals 键下设置此选项似乎已经被弃用。现在似乎需要设置一个 transform 选项。 - Ethan Kent
1
--maxWorkers=1 worked for me, as of 2022. isolatedModules did nothing. It actually increased my speed from 3.7s to 4.2s - GROVER.
显示剩余3条评论

30

阅读以下两个链接:

https://itnext.io/how-to-make-your-sluggish-jest-v23-tests-go-faster-1d4f3388bcdd https://github.com/facebook/jest/issues/7963

这里有一些可以考虑的事项。它们并不针对您的情况,但由于问题的标题比较通用,我认为它们可能会帮助某些访问者。不应该盲目尝试它们,它们只是研究的起点。

尝试加速jest测试的方法:

  1. 使用--watch模式运行

    Jest在使用--watch时进行了优化。

  2. 在主机计算机上运行而不是在Docker中运行? - 我以前使用 docker exec -it <containername> yarn test 运行,当我改为使用我的主机时发现它更快。

  3. 升级jest版本 似乎存在一些错误使某些版本变慢 https://github.com/facebook/jest/pull/8046

    注意: yarn upgrade 遵循 ~ 和 ^ 版本标识符, 如果您知道自己在做什么,可能只想删除并重新添加 yarn remove jest yarn add -D jest 这将使您获得最新版本

  4. 将测试环境从 jsdom 更改为 node

"jest": {
  "testEnvironment": "node"
}
  1. 同步运行测试... 允许Jest进行优化吗?

添加 --runInBand 选项

  1. 设置最大工作线程数可能会加快速度?

添加 --maxWorkers=4 选项

在我的情况下,我升级了Jest版本,开始使用 --watch 和 --runInBand,并在主机上而不是通过Docker运行,我的测试时间从2分钟降至10秒。我不知道问题具体出在哪里。


观察模式对我来说非常慢,但添加--runInBand修复了它。似乎工作池初始化需要大约20秒钟?我的测试套件很小,所以我不需要并行化。 - Caleb Miller
19
--runInBand 和 --maxWorkers 选项一起使用没有意义。 - Alexey Sh.
3
"--runInBand" 对我起到了修复作用。 - Nick Grealy
1
设置 testEnvironment: node 破坏了所有测试,因为 window 未定义,并且 runInBand 只在有少量测试时提供改进,但在运行 300 个套件时会大大减慢速度。如果您正在容器内运行并报告比实际拥有的 CPU 更多的情况,则 maxWorkers 可以很有用,但在我的情况下似乎没有什么作用。 - Jonathan Rys
关于runInBand,您也可以写一个百分比,例如maxWorkers:'25%'。 如果您与具有不同CPU规格的其他人共享存储库,则可能更好。 对我来说,这绝对比“runInBand”更快。 - Seega
显示剩余4条评论

26

2023 - 试试这个:

globals: {
  "ts-jest": {
    isolatedModules: true
  }
}

并运行

yarn test

17
为什么需要更多信息? - DarkTrick
1
也很好奇这为什么会使事情变得更快。在我的端上,运行单个虚拟测试的时间从大约8秒缩短到了大约2.5秒。谢谢! - berto
1
它跳过了TS检查和其他一些事情:https://huafu.github.io/ts-jest/user/config/isolatedModules - NickHTTPS
应该是被接受的答案。我的简单ts测试从4-5秒降至1-2秒。 - Gilad Gur
您值得一枚奖章。 - alsami
1
如果你收到一个弃用警告,请使用以下代码替代:transform: { "^.+\\.(t|j)sx?$": ['ts-jest', { isolatedModules: true }] } - undefined

25

解决方案:SWC(快速Web编译器)

ts-jest很可能会拖慢测试。

SWC是一个替代选择,用Rust编写,非常快。我获得了10倍以上的提升链接

安装

# if you use npm
npm i -D @swc/core @swc/jest

# if you use yarn
yarn add -D @swc/core @swc/jest

jest.config.js 中,配置 Jest 使用 SWC:

module.exports = {
  transform: {
    "^.+\\.(t|j)sx?$": ["@swc/jest"],
  },
};

使用方法

yarn jest --runInBand

注意:Jest版本28目前不稳定。我使用的是27.0.4

替代方案:ESBuild

你也可以使用用Go编写的esbuild,同样非常快速(与swc类似的性能)。

yarn add -D esbuild-jest esbuild

jest.config.js 中配置 Jest 使用 esbuild。
module.exports = {
  transform: {
    "^.+\\.(t|j)sx?$": ["esbuild-jest"],
  },
};

受到加速Jest的启发


1
这种方法比使用ts-jest要快得多。我认为在开发过程中不需要每次测试运行时都运行typescript,因为你的IDE将进行实时类型检查。只需确保在显式构建/CI期间运行typescript以确保类型错误不会滑漏即可。 - Hal
谢谢,这是我的基准测试结果: 没有使用 isolatedModules 的 ts-jest:2.7秒 / 使用 isolatedModules 的 ts-jest:1.2秒 / swc/jest:0.7秒 - Vincent
@swc/jest如果最终需要模拟某些模块,则毫无价值。@swc/jest没有正确实现@swc/jest,您需要诉诸这些丑陋的变通方法:https://www.npmjs.com/package/jest_workaround - undefined

5

我花了一段时间才找到这个混蛋。

最终对我有用的是对jest测试进行分析,并查找导致缓慢启动的原因。您可以使用this video来帮助。

对我来说,问题出在@mui/icons-material库上。卸载它后,单个文件的运行时间从5秒降至2秒。

我还发现了另一种方法:

// Instead of destructuring like such:
import { ExpandMore } from "@mui/icons-material"

// Directly importing speeds up by 3s
import ExpandMore from "@mui/icons-material/ExpandMore"

这个过程可以帮助您确定根本原因,但最终并不是解决方法。

相关链接:https://github.com/mui/material-ui/issues/12422

相关链接:https://github.com/facebook/jest/issues/10833#issuecomment-1192232331


这就是我的问题所在!当我停止导入指定的图标,并开始从它们自己的目录导入默认图标时,我的测试时间从534秒降至83秒。 - Stuart

3
我认为最终答案需要来自Angular团队。platformBrowserDynamicTesting的文档很少(https://angular.io/api/platform-browser-dynamic/testing/platformBrowserDynamicTesting)。也许platformBrowserDynamicTesting模拟了一个浏览器,并将整个DOM加载到内存中。在这种情况下,对于一个Angular应用程序(没有任何缓存的JavaScript),近10秒的启动时间似乎是合理的。也许我理解得不对,但根据您的报告,实际测试运行时间为6毫秒,似乎应该满足您的“快速测试”要求。如果您再添加另一个简单的“应该很快2”的测试,我很想看看测试需要多长时间。如果总时间仍然不到10秒,那么说明您的实际测试与Angular platformBrowserDynamicTesting工具的启动时间相比非常短。

3

我通过全局安装Jest解决了同样的问题。

npm install -g jest@26.0

以下是同一项目和测试用例的基准测试结果:

本地 - win10 版本2004 ----------------- -- node-14.7.0 -- 11.847秒

全局 - win10 版本2004 ----------------- -- node-14.7.0 -- 0.907秒

全局 - win10 版本2004 -- wsl/ubuntu-18.04 -- node-14.7.0 -- 0.469秒


1
对我来说没有任何区别(文件在Windows上,在git-bash中执行jest)。你在哪里运行测试,源文件存储在哪里?在Windows上还是在WSL中? - TmTron
今天我使用的是Windows10 + WSL2-Ubuntu,速度还算可以。测试文件在Windows分区中。我认为使用像nvm这样的工具或在本地运行jest可能是原因。但我没有确凿的证据。 - mustafa kemal tuna
4
尽管这个回答被多人踩了,但我给它点了赞。这正是情况所在。WSL2一直建议(官方建议)在Linux文件系统中访问文件比从Linux虚拟机访问Windows文件系统性能更好。这可能是一个例子。在某种程度上,这并不合理,因为即使全局安装jest也会将其二进制文件添加到Linux文件系统中(在我的情况下是/usr/bin/jest),但出于某种原因,它的工作速度快10倍。 要点概述: 要与npm一起使用,请使用:"test": "/usr/bin/jest"。 - aderchox
全局安装并本地卸载确实帮助我将时间从3.7秒减少到0.15秒,并且在测试开始之前的时间也显著缩短。我还使用WSL2与Ubuntu以及存储在Windows上的文件。 - s0up

2

我在我的Angular项目中也使用Jest,但我不确定这是否是一个好的解决方案。

当你配置你的测试模块时,你可以使用NO_ERRORS_SCHEMA,这样你就不必将所有嵌套组件添加到declarations中来编译你想要测试的组件。

beforeEach(async () => {
    return TestBed.configureTestingModule({
      declarations: [
        MyComponent
      ],
      schemas: [NO_ERRORS_SCHEMA]
    }).compileComponents();
  });

Jest 是单元测试,因此使用该解决方案,您只能测试组件。 如果要测试组件之间的交互,则需要使用 Protractor 或 Puppeteer 进行端到端测试。


1
我的测试由于faker的问题(版本:7.3.0),运行非常缓慢。使用const { faker } = require('@faker-js/faker/locale/en_US');代替const { faker } = require('@faker-js/faker');可以将require语句加速约50秒。请参考这里了解更多信息。

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接