让 Jest 运行得更快
但首先,我们需要了解为什么它这么慢。
实际例子
考虑一个简单的 React 组件。
import React from "react"; import { deepClone } from "./utils"; export function App() { const obj = { foo: 'bar' }; return ( <div> <p>Object looks like this: {JSON.stringify(deepClone(obj))}</p> </div> ); }
应用程序组件仅依赖于一个实用函数 - deepClone。 utils 文件如下所示。
import _ from 'lodash'; import moment from 'moment'; import * as mui from '@mui/material'; export const deepClone = (obj) => _.cloneDeep(obj); export const getFormattedDate = (date) => moment(date).format('YYYY-MM-DD'); export const isButton = (instance) => instance === mui.Button;
它导出三个单行辅助函数。就是这样。
现在,有一个大问题:您认为执行此测试需要多长时间?
import React from "react"; import { render, screen } from "@testing-library/react"; import { App } from "./app"; import "@testing-library/jest-dom"; test("renders the app", () => { render(<App />); });
答案是?永恒!
PASS src/tests/react-app/react-app.test.js √ renders the date and sum correctly (25 ms) Test Suites: 1 passed, 1 total Tests: 1 passed, 1 total Snapshots: 0 total Time: 5.045 s
在我的机器上花了 5 秒来为单行 React 组件执行单行测试用例。
分析绩效
要分析幕后发生的事情,我们可以使用 Chrome 的分析器 - 我建议观看 Kent C. Dodds 的这段富有洞察力的视频。
或者,您可以使用 jest-neat-runner 库,它可以简化分析过程。将 NEAT_REPORT_MODULE_LOAD_ABOVE_MS 选项设置为 150 并启用 NEAT_REPORT_TRANSFORM。此配置将打印出加载时间超过 150 毫秒的模块,并提供有关处理(打开和转译)文件所需时间的信息。
我们使用后者。这是输出。
> jest src/tests/react-app/ From src\tests\react-app\utils.js -> @mui/material in 1759ms From node_modules\@mui\material\node\styles\adaptV4Theme.js -> @mui/system in 509ms From src\tests\react-app\react-app.test.js -> @testing-library/react in 317ms From node_modules\@testing-library\react\dist\pure.js -> @testing-library/dom in 266ms From node_modules\@mui\system\ThemeProvider\ThemeProvider.js -> @mui/private-theming in 166ms From node_modules\@testing-library\dom\dist\role-helpers.js -> aria-query in 161ms
我们加载“@mui/material”库花了近 2 秒,甚至没有使用它!
许多项目的根本原因是什么?
凌乱的依赖关系
根据我的经验,jest 的性能问题主要源于大量甚至在运行时都没有使用的传递依赖项。正如上面的示例所示,如果您没有足够注意导入到应用程序中的文件,您最终可能会遇到与我相同的情况。
就我而言,App 组件仅依赖于 deepClone 实用函数。但是,由于 deepClone 是从 utils 文件导出的,因此 utils 文件中的所有依赖项也会随之加载。
包含大量松散相关函数和严重依赖项的文件可能会显着减慢您的应用程序和测试速度。
桶锉
Jest 不适合 ESM 模块,这导致它回退到 CommonJS。因此,tree-shaking 无法正常工作。当依赖从桶文件(索引文件)导入的模块时,这尤其成问题。
例如,当您从桶文件导入一个小组件或函数时,Jest 也会加载其他所有内容 - 这显然会导致不必要的开销。
现在怎么办?
手动调整导入策略
除了删除桶文件并通过将具有大量依赖项的文件分解为更小、更集中的模块来重构整个代码库之外。我们可以识别需要很长时间加载的模块并寻找较小的替代模块,或者检查导入的模块是否单独导出各个部分(即命名导入)而不是使用桶文件。
意思是,而不是
import React from "react"; import { deepClone } from "./utils"; export function App() { const obj = { foo: 'bar' }; return ( <div> <p>Object looks like this: {JSON.stringify(deepClone(obj))}</p> </div> ); }
做
import _ from 'lodash'; import moment from 'moment'; import * as mui from '@mui/material'; export const deepClone = (obj) => _.cloneDeep(obj); export const getFormattedDate = (date) => moment(date).format('YYYY-MM-DD'); export const isButton = (instance) => instance === mui.Button;
如果我们根本不使用该模块,我们可以通过 jest.mock 来模拟它,以避免完全加载它。
然而,这些调整可能相当耗时。
运行时缓存方法
更有效的方法是将 jest-neat-runner 库与 NEAT_RUNTIME_CACHE 选项一起使用。当此选项打开时,库会跟踪所有模块(每个测试文件)的实际运行时使用情况,并将后续测试运行不需要的依赖项存储到缓存中。让我在上面的示例中展示它的作用
import React from "react"; import { render, screen } from "@testing-library/react"; import { App } from "./app"; import "@testing-library/jest-dom"; test("renders the app", () => { render(<App />); });
我们通过跳过 26 个不必要的库(包括 MUI 库)的加载,将执行时间从 5 秒减少到 2 秒。
请小心 - 使用 NEAT_RUNTIME_CACHE 时有一些注意事项,因此请务必在使用前阅读 README。
其他优化技术
转译优化:检查需要转译的文件数量并使用最有效的转译器(例如 SWC 或 esbuild)。如果您想节省时间,jest-neat-runner 中的 NEAT_REPORT_TRANSFORM 选项将提供有关转译所需时间和模块数量的详细信息。
在内存中缓存模块:默认情况下,Jest 不会在内存中缓存模块,这意味着每次测试运行都必须打开、解析并将模块加载到内存中。如果您有大量测试和足够的内存,请考虑使用 NEAT_TRANSFORM_CACHE 选项来加快速度。
CI 管道怎么样?
并行运行:CircleCI 和 GitHub Actions 支持并行运行。这意味着您可以启动更多机器并使用 Jest 中的分片参数划分负载。
存储 Jest 和 Neat 缓存:这对于在 CI 中利用 Jest 和 jest-neat-runner 至关重要。请务必在 Jest 中设置 cacheDirectory 选项。然后,在测试运行后存储目录,并在运行测试之前恢复缓存。注意:如果您使用并行性,请确保为每个节点存储唯一的缓存。例如,CircleCI 公开了 CIRCLE_NODE_INDEX 环境变量,您可以在存储缓存时利用该变量。这就是它在 CircleCI 中的样子。
import React from "react"; import { deepClone } from "./utils"; export function App() { const obj = { foo: 'bar' }; return ( <div> <p>Object looks like this: {JSON.stringify(deepClone(obj))}</p> </div> ); }
通过遵循这些准则,您可以显着提高 Jest 在项目中的性能。
以上是让 Jest 运行得更快的详细内容。更多信息请关注PHP中文网其他相关文章!

热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

Video Face Swap
使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热门文章

热工具

记事本++7.3.1
好用且免费的代码编辑器

SublimeText3汉化版
中文版,非常好用

禅工作室 13.0.1
功能强大的PHP集成开发环境

Dreamweaver CS6
视觉化网页开发工具

SublimeText3 Mac版
神级代码编辑软件(SublimeText3)

不同JavaScript引擎在解析和执行JavaScript代码时,效果会有所不同,因为每个引擎的实现原理和优化策略各有差异。1.词法分析:将源码转换为词法单元。2.语法分析:生成抽象语法树。3.优化和编译:通过JIT编译器生成机器码。4.执行:运行机器码。V8引擎通过即时编译和隐藏类优化,SpiderMonkey使用类型推断系统,导致在相同代码上的性能表现不同。

Python更适合初学者,学习曲线平缓,语法简洁;JavaScript适合前端开发,学习曲线较陡,语法灵活。1.Python语法直观,适用于数据科学和后端开发。2.JavaScript灵活,广泛用于前端和服务器端编程。

从C/C 转向JavaScript需要适应动态类型、垃圾回收和异步编程等特点。1)C/C 是静态类型语言,需手动管理内存,而JavaScript是动态类型,垃圾回收自动处理。2)C/C 需编译成机器码,JavaScript则为解释型语言。3)JavaScript引入闭包、原型链和Promise等概念,增强了灵活性和异步编程能力。

JavaScript在Web开发中的主要用途包括客户端交互、表单验证和异步通信。1)通过DOM操作实现动态内容更新和用户交互;2)在用户提交数据前进行客户端验证,提高用户体验;3)通过AJAX技术实现与服务器的无刷新通信。

JavaScript在现实世界中的应用包括前端和后端开发。1)通过构建TODO列表应用展示前端应用,涉及DOM操作和事件处理。2)通过Node.js和Express构建RESTfulAPI展示后端应用。

理解JavaScript引擎内部工作原理对开发者重要,因为它能帮助编写更高效的代码并理解性能瓶颈和优化策略。1)引擎的工作流程包括解析、编译和执行三个阶段;2)执行过程中,引擎会进行动态优化,如内联缓存和隐藏类;3)最佳实践包括避免全局变量、优化循环、使用const和let,以及避免过度使用闭包。

Python和JavaScript在社区、库和资源方面的对比各有优劣。1)Python社区友好,适合初学者,但前端开发资源不如JavaScript丰富。2)Python在数据科学和机器学习库方面强大,JavaScript则在前端开发库和框架上更胜一筹。3)两者的学习资源都丰富,但Python适合从官方文档开始,JavaScript则以MDNWebDocs为佳。选择应基于项目需求和个人兴趣。

Python和JavaScript在开发环境上的选择都很重要。1)Python的开发环境包括PyCharm、JupyterNotebook和Anaconda,适合数据科学和快速原型开发。2)JavaScript的开发环境包括Node.js、VSCode和Webpack,适用于前端和后端开发。根据项目需求选择合适的工具可以提高开发效率和项目成功率。
