Tetapi pertama-tama, kita perlu faham mengapa ia begitu perlahan.
Pertimbangkan komponen React yang mudah.
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> ); }
Komponen apl hanya bergantung pada satu fungsi utiliti - deepClone. Fail utils kelihatan seperti ini.
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;
Ia mengeksport tiga fungsi pembantu satu baris. Itu sahaja.
Sekarang, inilah soalan besar: Pada pendapat anda, berapa lama masa yang diperlukan untuk melaksanakan ujian ini?
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 />); });
Jawapannya? Keabadian!
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
Ia mengambil masa 5 saat pada mesin saya, untuk melaksanakan kes ujian satu pelapik bagi komponen React satu pelapik.
Untuk menganalisis perkara yang berlaku di sebalik tabir, kita boleh menggunakan sama ada pemprofil Chrome - Saya syorkan menonton video bernas ini oleh Kent C. Dodds.
Sebagai alternatif, anda boleh menggunakan perpustakaan jest-neat-runner, yang memudahkan proses pemprofilan. Tetapkan pilihan NEAT_REPORT_MODULE_LOAD_ABOVE_MS kepada 150 dan dayakan NEAT_REPORT_TRANSFORM. Konfigurasi ini akan mencetak modul yang mengambil masa lebih daripada 150ms untuk dimuatkan dan memberikan maklumat tentang tempoh masa yang diambil untuk memproses (membuka dan mentranspile) fail.
Jom gunakan yang kedua. Ini adalah outputnya.
> 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
Kami memuatkan perpustakaan "@mui/material" selama hampir 2 saat tanpa menggunakannya!
Menurut pengalaman saya, masalah prestasi dengan gurauan terutamanya berpunca daripada bilangan besar kebergantungan transitif yang tidak digunakan pada masa jalanan. Seperti yang ditunjukkan dalam contoh kami di atas, jika anda tidak memberi perhatian yang cukup kepada fail yang anda import ke dalam aplikasi anda, anda mungkin akan mengalami situasi yang sama seperti saya.
Dalam kes saya, komponen App hanya bergantung pada fungsi utiliti deepClone. Walau bagaimanapun, memandangkan deepClone dieksport daripada fail utils, semua kebergantungan dalam fail utils turut dimuatkan bersamanya.
Fail yang mengandungi banyak fungsi berkaitan yang longgar dan kebergantungan berat mungkin melambatkan aplikasi dan ujian anda dengan ketara.
Jest bukan rakan dengan modul ESM, yang membawanya kepada sandaran kepada CommonJS. Akibatnya, goncangan pokok tidak berfungsi dengan betul. Ini amat bermasalah apabila bergantung pada modul yang diimport daripada fail tong (fail indeks).
Contohnya, apabila anda mengimport komponen atau fungsi kecil daripada fail tong, Jest akan memuatkan semua yang lain juga - yang jelas menyebabkan overhed yang tidak perlu.
Selain daripada mengalih keluar fail tong dan memfaktorkan semula keseluruhan pangkalan kod dengan memecahkan fail dengan banyak kebergantungan kepada modul yang lebih kecil dan lebih fokus. Kami boleh mengenal pasti modul yang mengambil masa yang lama untuk dimuatkan dan mencari modul alternatif yang lebih kecil atau menyemak sama ada modul yang diimport mengeksport bahagian individu secara berasingan (iaitu, import dinamakan) dan bukannya menggunakan fail tong.
Maksudnya, bukannya
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> ); }
buat
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;
Jika kami tidak menggunakan modul itu sama sekali, kami boleh mengejeknya melalui jest.mock untuk mengelakkan memuatkannya sepenuhnya.
Walau bagaimanapun, pelarasan ini boleh memakan masa yang agak lama.
Kaedah yang lebih berkesan melibatkan penggunaan perpustakaan jest-neat-runner dengan pilihan NEAT_RUNTIME_CACHE. Apabila pilihan ini dihidupkan, pustaka menjejaki penggunaan masa jalan sebenar semua modul (setiap fail ujian) dan menyimpan kebergantungan yang kami tidak perlukan untuk ujian berikutnya dijalankan ke dalam cache. Biar saya tunjukkan fungsinya pada contoh di atas
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 />); });
Kami mengurangkan masa pelaksanaan daripada lima saat kepada dua dengan melangkau memuatkan 26 perpustakaan yang tidak diperlukan, termasuk perpustakaan MUI.
Berhati-hati - terdapat beberapa kaveat apabila menggunakan NEAT_RUNTIME_CACHE, jadi pastikan anda membaca README sebelum menggunakannya.
Pengoptimuman transpilasi: Periksa bilangan fail yang perlu ditranpilkan dan gunakan transpiler yang paling berkesan (seperti SWC atau esbuild). Jika anda ingin menjimatkan masa, pilihan NEAT_REPORT_TRANSFORM dalam jest-neat-runner akan memberikan maklumat terperinci tentang berapa banyak masa dan berapa banyak modul yang diperlukan untuk transpile.
Caching Modul dalam Memori: Secara lalai, Jest tidak cache modul dalam memori, bermakna setiap ujian dijalankan mesti membuka, menghuraikan dan memuatkan modul ke dalam memori. Jika anda mempunyai rangkaian ujian yang luas dan ingatan yang mencukupi, pertimbangkan untuk menggunakan pilihan NEAT_TRANSFORM_CACHE untuk mempercepatkan perkara.
Larian Selari: CircleCI dan Tindakan GitHub menyokong larian selari. Ini bermakna anda boleh memutarkan lebih banyak mesin dan membahagikan beban menggunakan parameter shard dalam Jest.
Menyimpan Cache Jest dan Rapi: Ini penting untuk memanfaatkan Jest dan jest-neat-runner dalam CI. Pastikan anda menetapkan pilihan cacheDirectory dalam Jest. Kemudian, simpan direktori selepas ujian dijalankan dan pulihkan cache sebelum menjalankan ujian. Kaveat: Jika anda menggunakan selari, pastikan anda menyimpan cache unik untuk setiap nod. Sebagai contoh, CircleCI mendedahkan pembolehubah persekitaran CIRCLE_NODE_INDEX, yang boleh anda manfaatkan apabila menyimpan cache. Beginilah rupanya dalam 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> ); }
Dengan mengikut garis panduan ini, anda boleh meningkatkan prestasi Jest dengan ketara dalam projek anda.
Atas ialah kandungan terperinci Mari Jadikan Jest Berlari Lebih Pantas. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!