Anda mungkin berada di salah satu situasi berikut. Entah proyek JavaScript Anda hampir tidak memiliki tes dan setiap refactor terasa berisiko, atau Anda sudah memiliki tes dan setengah dari mereka lambat, rapuh, dan sulit dipercaya.
Itu akan semakin buruk di Capacitor dan aplikasi Electron. Aplikasi sederhana dapat menyentuh logika bisnis bersamaan, API browser, plugin native, file lokal, IPC, dan layanan jarak jauh dalam aliran yang sama. Jika Anda menguji bagian-bagian tersebut dengan cara yang salah, suite Anda akan menjadi labirin dari dependensi palsu. Jika Anda mengujinya dengan cara yang tepat, Anda akan mendapatkan feedback cepat pada logika yang rusak.
Unit Test yang Baik
Unit test JavaScript tidak dimulai dengan sintaks matcher yang cerdas. Ini dimulai dengan batasan yang disiplin: uji logika murni secara langsung, isolasi efek sampingan, dan hindari menulis unit test yang runtuh ketika Anda mengubah nama fungsi internal.
- Tabel Konten
- Rekomendasi saya untuk tim kebanyakan
- Menguasai Mocks dan Asynchronous Code
- Strategi Lanjutan untuk Tes yang Kuat
- Menguji untuk CI, Capacitor, dan Aplikasi Electron
- Mengenai Pertanyaan yang Sering Diajukan Tentang Pengujian Satuan JavaScript
Pemilihan Framework Pengujian JavaScript Anda
Proyek JavaScript profesional membutuhkan runner tes yang nyata. Skrip ad hoc dan pengecekan console manual tidak dapat berkembang ketika beberapa insinyur menyentuh kodebase yang sama. Anda membutuhkan penemuan tes, asserasi, penanganan async, mock, dan cara menjalankan semuanya secara konsisten dalam pengembangan lokal dan CI.
Guidance saat ini terus berkonvergensi pada beberapa pilihan mainstream yang kecil. Jest, Mocha, dan Jasmine sering kali dianggap sebagai framework utama, dengan Jest seringkali dipilih karena struktur tes bawaan, asseri, mocking, dan dukungan async dalam satu paket, seperti yang ditunjukkan di Lab Tes JavaScript Pluralsight.

Mengapa framework bukanlah hal yang opsional
Kesalahan pertama tim membuat adalah menganggap tes unit sebagai kegiatan sampingan. Biasanya hal ini menyebabkan penamaan file tidak konsisten, asseri custom yang tidak diingat, dan helper yang hanya dipahami oleh satu orang.
Framework memberikan Anda bahasa bersama:
- Struktur Tes dengan
describedantestatauit - Asseri dengan matcher yang dapat dibaca
- Hooks untuk pengaturan dan pembersihan
- Support Asinkron untuk janji dan timer
- Alat Palsu untuk ketergantungan luar
Jika tim Anda juga membutuhkan pandangan yang lebih luas tentang otomatisasi tes di luar pekerjaan tingkat unit, Capgo memiliki ringkasan yang berguna tentang pengujian otomatis dalam alur pengiriman aplikasi.
Jest vs Mocha secara singkat
Jest dan Mocha mewakili dua filosofi yang berbeda.
Jest adalah pilihan semua dalam satu. Ia dilengkapi dengan sebagian besar yang dibutuhkan tim pada hari pertama.
Mocha lebih modular. Ini memberikan Anda runner dan mengharapkan Anda untuk menyusun sisa dari stack. Fitur
| Jest | Mocha | Kompleksitas pengaturan |
|---|---|---|
| Rendah untuk tim kebanyakan | Tinggi karena biasanya Anda menambahkan library asertasi dan mocking | Asertasi |
| Terintegrasi | Sering digunakan bersama dengan library lain | Palsu |
| __CAPGO_KEEP_0__ | Dibangun dalam | Biasanya dipasangkan dengan library lain |
| Pengujian async | Dibangun dan sederhana | Disediakan, tetapi tergantung lebih pada pengaturan sekitar |
| Alur kerja coverage | Biasanya diintegrasi ke dalam rantai alat yang sama | Seringkali lebih terpisah-pisah |
| Pilihan terbaik | Proyek baru, tim yang ingin konsistensi | Stack legacy, tim yang ingin kontrol modular |
Aturan praktis: Jika tim Anda harus bertanya-tanya perpustakaan asertasi mana dan perpustakaan mocking yang harus dipasangkan dengan runner, kemungkinan besar Anda ingin menggunakan Jest.
Rekomendasi saya untuk tim kebanyakan
Untuk proyek modern kebanyakan, saya akan memilih Jest kecuali kodebase sudah memiliki alasan kuat untuk tetap menggunakan Mocha. Rekomendasi ini semakin kuat ketika aplikasi termasuk Capacitor atau Electron, karena proyek-proyek tersebut sudah memiliki cukup banyak bagian yang bergerak. Mengurangi penyebaran alat uji membayar cepat.
Mocha masih relevan dalam layanan Node.js yang lebih tua atau kodebase yang sudah lama, karena ekosistem di sekitarnya sudah terbiasa. Tapi untuk insinyur mid-level yang mengatur suite yang kuat dari awal, Jest biasanya mengurangi gesekan lebih banyak daripada yang dibuat.
Catatan penting satu. Cypress dan Playwright adalah alat-alat yang sangat baik, tapi mereka menyelesaikan masalah yang berbeda. Mereka lebih baik untuk pengujian browser-level dan end-to-end, bukan loop inner yang cepat di mana pengujian unit JavaScript harus hidup.
Pengaturan Proyek dan Pengujian Pertama Anda
Suatu setup pengujian yang bersih haruslah membosankan. Jika menambahkan tes pertama terasa rumit, maka suite tersebut mungkin tidak akan tetap sehat.

Setup Jest yang sederhana
Mulai dengan proyek JavaScript yang sudah memiliki package.json. Kemudian tambahkan Jest sebagai dependensi pengembangan dan hubungkan skrip pengujian.
{
"scripts": {
"test": "jest"
}
}
Itu sudah cukup untuk banyak proyek. Anda dapat menambahkan konfigurasi lebih lanjut jika sistem modul, transpilasi, atau struktur monorepo memerlukan.
Jika Anda sedang membangun aplikasi Capacitor secara lokal dan ingin lingkungan pengembangan Anda dalam kondisi sebelum menambahkan tes di sekitar logika bersama, Capgo's guide untuk mengatur lingkungan lokal Capacitor adalah mitra yang praktis.
Tulis tes sebelum code
Polanya tes pertama bukan hanya preferensi pribadi. Biro Perlindungan Konsumen Keuangan Amerika Serikat dalam panduan JavaScriptnya secara eksplisit merekomendasikan menulis tes pertamaMengorganisir tes dengan describe dan itMengatur cek sekitar expect(...) klaim dalam panduan tes unit JavaScriptnya Hal ini penting karena perubahan test-first mengubah cara Anda merancang __CAPGO_KEEP_0__. Fungsi cenderung menjadi lebih kecil, dependensi menjadi lebih terlihat, dan efek sampingan berhenti mengalir ke logika yang seharusnya tetap murni..
That matters because test-first changes how you design code. Functions tend to become smaller, dependencies become more visible, and side effects stop leaking into logic that should stay pure.
Pakai Arrange Act Assert setiap kali
// math.js
function addTax(amount, rate) {
return amount + amount * rate;
}
module.exports = { addTax };
// math.test.js
const { addTax } = require('./math');
describe('addTax', () => {
it('returns the amount with the tax applied', () => {
expect(addTax(100, 0.2)).toBe(120);
});
});
Patron
Arrange, Act, Assert menggunakan tes tetap dapat dibaca, bahkan ketika mereka menjadi lebih kompleks. Arrange
- Act Masukkan input dan konfigurasi yang dibutuhkan.
- Act melakukan panggilan fungsi.
- Assert mengenai hasilnya.
Aplikasikan pada bantuan validasi:
function isSupportedPlatform(platform) {
return ['ios', 'android', 'web', 'desktop'].includes(platform);
}
describe('isSupportedPlatform', () => {
it('returns true for ios', () => {
// Arrange
const platform = 'ios';
// Act
const result = isSupportedPlatform(platform);
// Assert
expect(result).toBe(true);
});
});
Uji coba kecil bertahan lama. Sebuah uji coba biasanya harus menjawab satu pertanyaan, bukan menceritakan alur kerja yang lengkap.
Untuk Capacitor dan proyek Electron, disiplin itu lebih penting karena logika yang murni sering berada di samping integrasi native atau desktop code. Pastikan aturan bisnis dapat diuji tanpa runtime platform, dan uji coba pertama Anda tidak akan menjadi uji coba yang berguna terakhir.
Menguasai Mocks dan Asynchronous Code
Banyak bug di aplikasi code tidak berasal dari penjumlahan dua angka. Mereka berasal dari code yang mencapai luar diri: permintaan jaringan, file, API plugin, timer, saluran IPC, lapisan penyimpanan.
Itu adalah tempat di mana mocking membantu. Mocking memberikan kontrol atas batasan sehingga uji coba dapat fokus pada keputusan code.

Batasi batasan, bukan semuanya
Panduan tes yang dapat dipelihara menekankan penutupan perilaku tunggal dan pernyataan kuat satu per tes, dan juga mengingatkan bahwa menggunakan mock yang berlebihan membuat tes menjadi rapuh dan terikat pada detail implementasi, seperti yang disingkatkan dalam artikel TestRail tentang tes unit yang dapat dipelihara Pentingnya peringatan itu sangat besar dalam JavaScript. Tim sering kali memulai dengan mengmock semua modul yang diimport dan akhirnya menguji apakah fungsi memanggil fungsi lain dalam urutan yang .
Tujuan buruk untuk tes yang berat mock:
apakah helper A memanggil helper B
- apakah service C memanggil serializer D
- apakah fungsi privat internal berjalan dua kali
- apakah helper A memanggil helper B
Target yang lebih baik:
- apa yang dikembalikan oleh fungsi
- apakah itu menangani ketergantungan yang gagal dengan benar
- apakah itu mengubah data menjadi bentuk yang diharapkan
Polanya yang lebih baik untuk Capacitor dan Electron code
Pada aplikasi mobile dan desktop, saya lebih suka layer pelapis di sekitar API native atau platform. Kemudian unit tests memalsukan layer pelapis, bukan platform itu sendiri.
Struktur contoh:
// cameraGateway.js
async function getPhoto(cameraPlugin) {
return cameraPlugin.getPhoto();
}
module.exports = { getPhoto };
// profilePhotoService.js
async function loadProfilePhoto(cameraGateway) {
const photo = await cameraGateway.getPhoto();
return { path: photo.path, ready: true };
}
module.exports = { loadProfilePhoto };
// profilePhotoService.test.js
const { loadProfilePhoto } = require('./profilePhotoService');
test('returns mapped photo data', async () => {
const fakeCameraGateway = {
getPhoto: jest.fn().mockResolvedValue({ path: '/tmp/pic.jpg' })
};
const result = await loadProfilePhoto(fakeCameraGateway);
expect(result).toEqual({ path: '/tmp/pic.jpg', ready: true });
});
Gaya pola itu juga berlaku untuk Electron. Tutup ipcRendererAkses file, atau integrasi shell di balik adapter tipis. Unit tests menghantam layer layanan, bukan runtime secara langsung.
Untuk tim yang menguji logika rilis dan jalur pembaruan di Capacitor aplikasi, Capgo memiliki panduan relevan tentang menguji pembaruan OTA Capacitor dengan skenario palsu.
Ringkasan singkat membantu jika tim Anda masih mengnormalisasi gaya tes async:
Tes aliran async tanpa fluktuasi
Menggunakan async/await dalam tes ketika code yang sedang dites mengembalikan janji. Lebih jelas daripada pola callback yang berat dan lebih mudah untuk di-debug.
async function fetchProfile(api) {
const response = await api.getUser();
return response.name;
}
test('returns the user name from the API response', async () => {
const api = {
getUser: jest.fn().mockResolvedValue({ name: 'Ava' })
};
const result = await fetchProfile(api);
expect(result).toBe('Ava');
});
Juga tes jalur gagal:
test('throws when the API request fails', async () => {
const api = {
getUser: jest.fn().mockRejectedValue(new Error('network failed'))
};
await expect(fetchProfile(api)).rejects.toThrow('network failed');
});
Tes baik jalur yang bahagia dan jalur yang tidak enak. Di produksi, jalur yang tidak enak biasanya adalah yang pengguna ingat.
Strategi Lanjutan untuk Tes yang Kuat
Sebuah suite tes menjadi berguna ketika tetap berguna setelah code berubah. Itu lebih sulit daripada menulis tumpukan tes yang berhasil.

Gunakan pembagian tes sebagai anggaran
Satu panduan praktis merekomendasikan 70/20/10 pembagian sebesar across tes unit, integrasi, dan tes akhir-ke-akhiranbersama dengan unit test yang memberikan feedback yang paling cepat dan kegagalan yang paling stabil. Panduan yang sama mengatakan bahwa suite unit penuh seharusnya selesai dalam kurang dari 10 detik, dan periksa pre-commit seharusnya tetap kurang dari 5 detik, menurut panduan pengujian OpenReplay ini Saya menganggap itu sebagai alat anggaran, bukan agama. Jika sebagian besar upaya Anda berada di uji coba end-to-end, tim Anda akan menunggu terlalu lama untuk mendapatkan feedback. Jika semuanya hanya unit-only, Anda akan melewatkan batasan sistem nyata..
Untuk aplikasi __CAPGO_KEEP_0__ atau Electron, keseimbangan yang sehat biasanya terlihat seperti ini:
For a Capacitor or Electron app, a healthy balance usually looks like this:
- untuk logika harga, aturan akses, penguraian data, kelayakan pembaruan, flag fitur, dan transformasi keadaan Uji integrasi
- untuk penggunaan penyimpanan, penggunaan wrapper plugin, dan kontrak IPC bersama dengan unit test yang memberikan feedback yang paling cepat dan kegagalan yang paling stabil. Panduan yang sama mengatakan bahwa suite unit penuh seharusnya selesai dalam kurang dari 10 detik, dan periksa pre-commit seharusnya tetap kurang dari 5 detik, menurut panduan pengujian OpenReplay ini Saya menganggap itu sebagai alat anggaran, bukan agama. Jika sebagian besar upaya Anda berada di uji coba end-to-end, tim Anda akan menunggu terlalu lama untuk mendapatkan feedback. Jika semuanya hanya unit-only, Anda akan melewatkan batasan sistem nyata. Untuk aplikasi __CAPGO_KEEP_0__ atau Electron, keseimbangan yang sehat biasanya terlihat seperti ini: Uji unit untuk logika harga, aturan akses, penguraian data, kelayakan pembaruan, flag fitur, dan transformasi keadaan Uji integrasi untuk penggunaan penyimpanan, penggunaan wrapper plugin, dan kontrak IPC
- Uji Akhir-akhir untuk beberapa perjalanan kritikal seperti login, alur pembelian, sinkron, atau permintaan pembaruan
Koverasi adalah senter, bukan sasaran
Laporan koverasi berguna ketika membantu Anda menemukan cabang yang belum diuji dalam logika penting. Mereka menjadi berbahaya ketika tim mengejar persentase koverasi untuk kepentingan mereka sendiri.
Validator login dengan uji kasus tepat memberikan nilai lebih dari file yang terlindungi penuh dengan asertasi trivial. Hal itu terutama benar untuk input-heavy code seperti formulir, parser, logika tanggal, dan periksa izin. Jika tim Anda memperketat kualitas di sekitar validasi UI berat, panduan ini tentang menguasai validasi formulir frontend adalah komplement yang baik untuk strategi pengujian tingkat unit.
Pengujian perilaku pertama dapat bertahan dari refactor
Suit pengujian yang dapat diandalkan harus memungkinkan Anda merubah internal tanpa menulis ulang setengah dari pengujian. Cara termudah untuk mencapai hal itu adalah dengan mengklaim perilaku yang dapat diamati bukan detail implementasi.
Penggunaan yang dapat bertahan dengan baik:
- Kondisi batas seperti input kosong, nilai null, jenis data tidak valid, dan string yang terlalu besar
- Akibat domain seperti “pengembalian ditolak karena izin yang hilang”
- Transisi keadaan seperti “mengupdate sebagai menunggu setelah metadata diunduh diverifikasi”
Penggunaan kasus yang sering rusak:
- menginspeksi panggilan helper internal
- mengklaim metode privat yang berurutan
- menggagalkan setiap lapisan dalam rantai panggilan
Untuk tim aplikasi yang membangun proses rilis yang disiplin, Capgo’s artikel tentang jaminan kualitas aplikasi adalah berguna karena menghubungkan pekerjaan tes ke jalur pipa rilis yang lebih luas.
Pengujian untuk CI, Capacitor, dan Aplikasi Electron
Suatu tes yang hanya berjalan di satu mesin pengembang bukanlah jaring pengaman. Itu adalah kebiasaan lokal.
CI mengubah tes unit kerja JavaScript menjadi infrastruktur tim. Setiap push, permintaan pull, atau cabang rilis dapat menguji perintah yang sama dengan harapan yang sama. Konsistensi itu lebih penting lagi untuk Capacitor dan proyek Electron, di mana pergeseran lingkungan menyebabkan gagal yang halus.
Buat CI sebagai jalur eksekusi default
Paling tidak, CI Anda harus menginstal dependensi dan menjalankan suite unit pada setiap set perubahan. Simpan perintah identik dengan pengembangan lokal saat mungkin.
Contoh workflow GitHub Actions yang sederhana bisa sekecil ini:
name: test
on: [push, pull_request]
jobs:
unit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- run: npm ci
- run: npm test
Itu sudah cukup untuk menangkap import yang rusak, asertasi yang gagal, dan asumsi platform yang tidak sengaja sebelum mereka mendarat di utama.
Untuk tim mobile yang mengirimkan melalui pipa otomatis, Capgo memiliki panduan praktis untuk mengatur CI/CD untuk aplikasi Capacitor.
Menguji interaksi plugin Capacitor
Cara yang salah untuk menguji unit Capacitor code adalah dengan menarik plugin native secara langsung ke dalam setiap layanan. Itu akan mengkopi tes suite Anda ke jembatan platform.
Pola yang lebih baik adalah abstraksi tipis:
// deviceStorage.js
async function saveFile(filesystem, path, data) {
return filesystem.writeFile({ path, data });
}
module.exports = { saveFile };
// draftService.js
async function persistDraft(storage, draft) {
await storage.save('draft.json', JSON.stringify(draft));
return { saved: true };
}
module.exports = { persistDraft };
// draftService.test.js
const { persistDraft } = require('./draftService');
test('persists a serialized draft', async () => {
const storage = {
save: jest.fn().mockResolvedValue(undefined)
};
const result = await persistDraft(storage, { title: 'Hello' });
expect(result).toEqual({ saved: true });
});
Idea yang sama berlaku untuk akses kamera, prompt biometrik, pendaftaran token push, dan status jaringan. Tahan panggilan plugin di adapter. Uji logika aplikasi terhadap interface yang dikendalikan.
Menguji Electron main renderer dan IPC code
Aplikasi Electron memiliki dua celah penting: proses utama code dan proses renderer code. Jangan kaburkan mereka dalam uji coba.
Konfigurasi yang dapat diandalkan biasanya memisahkan:
- Uji unit proses renderer untuk model tampilan, keadaan, pengaturan format, dan logika bisnis sisi UI
- Uji unit proses utama untuk menu, operasi file, dan keputusan siklus aplikasi
- tes kontrak IPC untuk bentuk pesan dan respons yang diharapkan
Contoh wrapper IPC:
// ipcGateway.js
function sendSettings(ipcRenderer, payload) {
ipcRenderer.send('settings:update', payload);
}
module.exports = { sendSettings };
// ipcGateway.test.js
const { sendSettings } = require('./ipcGateway');
test('sends settings update over ipc', () => {
const ipcRenderer = { send: jest.fn() };
sendSettings(ipcRenderer, { theme: 'dark' });
expect(ipcRenderer.send).toHaveBeenCalledWith('settings:update', { theme: 'dark' });
});
Jika Anda kemudian mengubah implementasi internal dari satu bantuan ke bantuan lain, tes ini masih berlaku karena memverifikasi perilaku yang berlaku. Itu adalah standar yang Anda inginkan di desktop dan mobile code.
Tanya-Tanya Sering Ditanyakan Tentang Unit Testing JavaScript
Apa perbedaan antara unit integration dan E2E tests
A unit test menguji satu bagian logika kecil secara isolasi. Sebuah integration test menguji apakah beberapa komponen atau layanan bekerja bersama-sama dengan benar. Sebuah tes akhir ke akhir menguji perjalanan pengguna melalui aplikasi yang berjalan.
Pakai unit test untuk kepercayaan cepat pada aturan bisnis. Pakai tes integrasi untuk sambungan-sambungan seperti penyimpanan, wrapper plugin, dan IPC. Pakai tes E2E dengan sedikit untuk alur kerja yang akan sangat terganggu jika mereka rusak.
Apakah kita harus mencapai coverase penuh
Tidak. Coverase penuh dapat mendorong tim ke tes-tes yang tidak berharga.
Coverase berguna ketika menunjukkan risiko code yang belum pernah diuji. Tidak berguna ketika insinyur menambahkan asseri yang dangkal hanya untuk memuaskan dashboard. Jika suite Anda sangat rapuh, coverase yang lebih banyak tidak akan menyelamatkannya.
Bagaimana kita menambahkan tes ke basis kode yang sudah ada
Mulai dari tempat perubahan sudah terjadi. Jangan membuat tim beku dan mengumumkan perubahan besar pada strategi tes.
Sebuah urutan yang praktis seperti ini:
- Pertahankan code yang aktif terlebih dahulu Dengan menambahkan tes ke modul yang Anda sentuh selama pekerjaan fitur atau perbaikan bug
- Ekstrak logika yang murni dari file yang sulit diuji sehingga aturan bisnis dapat diuji tanpa kebisingan framework atau runtime
- Tambahkan wrapper jahitan di sekitar plugin native, klien jaringan, panggilan filesystem, dan IPC Electron
- Tolak pola yang rapuh ketika memperkenalkan mock. Panduan dari praktik pengujian JavaScript terbaik terutama berguna di sini karena menyoroti masalah yang sering terlewatkan yaitu over-mocking dan tes yang rapuh yang mengikuti
Tujuan bukanlah kesempurnaan segera. Itu adalah perbaikan yang stabil di tempat-tempat di mana regresi menghabiskan tim paling banyak.
Jika tim Anda mengirimkan Capacitor atau Electron Aplikasi dan kebutuhan sebuah proses rilis yang lebih bersih seputar perubahan JavaScript, Capgo adalah salah satu pilihan untuk dilihat. Ini menyediakan pembaruan langsung untuk aplikasi CapacitorJS dan Electron, dengan kontrol peluncuran dan observabilitas, sehingga tim dapat memadukan unit testing yang solid dengan jalur yang lebih aman untuk mengirimkan perubahan bundle web tanpa harus menunggu tinjauan toko untuk setiap perbaikan.