Saltare al contenuto principale

Unit Tests JavaScript: Guida completa 2026

Impara a gestire i test unitari del JavaScript con la nostra guida 2026. Copre Jest, Mocha, configurazione, simulazione, CI e consigli per l'applicazione Capacitor & Electron.

Unit Tests JavaScript: Guida completa 2026

Siete probabilmente in una delle due situazioni. O il vostro progetto JavaScript ha quasi nessun test e ogni refactor sembra rischioso, o già avete test e la metà di essi sono lenti, fragili e difficili da fidarsi.

Che peggiora in Capacitor e Electron applicazioni. Una semplice funzionalità può influire sulla logica di business condivisa, sulle API del browser, sui plugin nativi, sui file locali, sulle comunicazioni interprocesso e sui servizi remoti nello stesso flusso. Se testi quei pezzi in modo sbagliato, il tuo set di test diventa un labirinto di dipendenze fake. Se li testi nel modo giusto, ottieni feedback rapido sulla logica che si rompe.

Le buone unit test JavaScript non iniziano con la sintassi dei matcher astuti. Iniziano con un confine disciplinato: testa la logica pura direttamente, isolare gli effetti collaterali e evita di scrivere test che si sbriciolano non appena rinomini una funzione interna.

Tavola dei Contenuti

Scegliere il tuo framework di testing JavaScript

Un progetto di JavaScript professionale ha bisogno di un vero e proprio esecutore di test. Gli script ad hoc e le verifiche manuali della console non scalano quando più ingegneri toccano lo stesso codice. Serve la scoperta dei test, le affermazioni, la gestione degli eventi asincroni, i mock e un modo per eseguire tutto in modo coerente nel development locale e CI.

La guida attuale converge sempre più su una piccola serie di opzioni mainstream. Jest, Mocha e Jasmine sono spesso evidenziati come i principali framework, con Jest spesso isolato per la struttura di test integrati, le asserzioni, il mocking e il supporto asincrono in un unico pacchetto, come mostrato in questo Lab di test JavaScript di Pluralsight.

Tabella di confronto dei framework di test JavaScript popolari, inclusi Jest, Mocha, Cypress e Playwright.

Perché un framework non è facoltativo

Il primo errore che le squadre commettono è trattare i test unitari come un'attività secondaria. Ciò porta spesso a nomi di file inconsistenti, asserzioni personalizzate che nessuno ricorda e aiuti che solo una persona comprende.

Un framework vi offre un linguaggio condiviso:

  • Struttura di test con describe o test asserzioni it
  • con matcher leggibili e con matcher leggibili
  • Hook per la configurazione e la pulizia
  • Sostegno asincrono per promesse e timer
  • Strumenti di simulazione per dipendenze esterne

If your team also needs a broader view of test automation beyond unit-level work, Capgo has a useful overview of Automazione dei test nell'ambito dei flussi di consegna di applicazioni.

Jest vs Mocha in una sola occhiata

Jest e Mocha rappresentano due filosofie diverse.

Jest è l'opzione tutto in uno. Viene fornito con la maggior parte di ciò di cui le squadre hanno bisogno già dal primo giorno.
Mocha è più modulare. Gli fornisce un esecutore e ti aspetta che tu assembli il resto della pila.

Caratteristica Jest Mocha
Complessità di configurazione In generale più bassa per la maggior parte delle squadre Maggiore perché di solito aggiungi librerie di assert e mocking
Assert Incoraggiato Di solito associato a un'altra libreria
Mocking Integrato Di solito associato ad un'altra libreria
Test di asincronia Integrato e diretto Supportato, ma dipende di più dalla configurazione circostante
Flusso di copertura Comunemente integrato nello stesso chain tool Spesso più frammentato
Miglior adattamento Nuovi progetti, team che desiderano coerenza Pilette di legacy, team che desiderano controllo modulare

Regola pratica: Se il tuo team deve chiedere quale libreria di affermazione e quale libreria di simulazione utilizzare con il runner, probabilmente vuoi Jest.

Quello che consiglio per la maggior parte dei team

Per la maggior parte dei progetti moderni, sceglierei Jest se non ci sono forti motivi per cui il codicebase deve rimanere su Mocha. Questa raccomandazione diventa più forte quando l'applicazione include Capacitor perché quei progetti già hanno abbastanza parti in movimento. Ridurre la dispersione di strumenti di testing rende i frutti velocemente. Mocha è ancora sensato in servizi Node.js più vecchi o in codebase a lunga vita dove l'ecosistema che lo circonda è già stabilito. Ma per un ingegnere di livello medio che sta configurando un robusto set da zero, Jest rimuove di solito più frizione di quella che crea.Un importante nota di campo. Cypress e Playwright sono eccellenti strumenti, ma risolvono un problema diverso. Sono meglio per i controlli di browser e di fine a fine, non per il rapido ciclo interno dove i test di unità JavaScript dovrebbero vivere.

Configurazione del Progetto e il tuo Primo Test

Elettronica

perché quei progetti già hanno abbastanza parti in movimento. Ridurre la dispersione di strumenti di testing rende i frutti velocemente.

A un setup di testing pulito dovrebbe essere noioso. Se aggiungere il primo test sembra complicato, il suite probabilmente non resterà sano.

Un uomo con gli occhiali che lavora su un progetto di programmazione su un laptop su un tavolo di legno.

Un setup Jest semplice

Inizia con un progetto JavaScript che già ha un package.jsonQuindi aggiungi Jest come dipendenza di sviluppo e collega uno script di test.

{
  "scripts": {
    "test": "jest"
  }
}

Questo è sufficiente per molti progetti. Puoi aggiungere ulteriori configurazioni in seguito se il tuo sistema di moduli, la transpilazione o la struttura di monorepo richiedono.

Se stai costruendo un'app locale con Capacitor e vuoi che il tuo ambiente di sviluppo sia in ordine prima di aggiungere i test intorno alla logica condivisa, il Capgo's guida per Capacitor l'ambiente locale setting up a Capacitor local environment Scrivi il test prima del __CAPGO_KEEP_0__

Write the test before the code

scrivere il test prima Un ambiente locale di sviluppo, organizzare i test con describe e it, e definire i controlli intorno expect(...) asserzioni nel suo guida di testing unitario JavaScript.

È importante perché il test-first cambia la maniera in cui si progetta code. Le funzioni tendono a diventare più piccole, le dipendenze diventano più visibili, e gli effetti collaterali smettono di infiltrarsi nella logica che dovrebbe rimanere pura.

Ecco un esempio minimo:

// 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);
  });
});

Usare Arrange Act Assert ogni volta

La pattern di Arrange, Act, Assert mantiene i test leggibili, anche quando diventano più complessi.

  1. Arrange l'input e qualsiasi configurazione necessaria.
  2. Agisci chiamando la funzione.
  3. Assicura sul risultato.

Applicato a un helper di validazione:

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);
  });
});

Le piccole prove invecchiano bene. Una prova dovrebbe rispondere di solito a una sola domanda, non narrare un intero workflow.

Per i progetti Capacitor e Electron, quella disciplina conta più perché la tua logica pura spesso si trova accanto all'integrazione nativa o desktop code. Mantieni la regola commerciale testabile senza il runtime della piattaforma, e la tua prima prova non sarà l'ultima utile.

Maestri di Mock e Asincrono Code

La maggior parte dei bug negli applicativi code non proviene dall'aggiunta di due numeri. Proviene da code che raggiunge al di fuori di sé: richieste di rete, file, plugin API, timer, canali IPC, layer di archiviazione.

È là che aiuta il mocking. Ti dà il controllo sul confine affinché la prova possa concentrarsi sulla decisione di code.

Un diagramma a quadretti che illustra un'architettura di microservizi con API, archivi di dati, servizi esterni e flusso di dati guidato dagli eventi.

Delimita i confini, non tutto

La guida per le prove mantenibili enfatizza La copertura della singola comportamento e una sola affermazione forte per la prova, e inoltre avverte che l'uso eccessivo dei mock rende le prove fragili e legate ai dettagli di implementazione, come riassunto in questo Articolo di TestRail sulla prova unitaria mantenibile.

Questo avvertimento conta molto in JavaScript. Le squadre spesso iniziano facendo mock di ogni modulo importato e finiscono per testare se le funzioni chiamano altre funzioni nell'ordine 'corretto', invece di testare il comportamento reale.

Obiettivo sbagliato per una prova pesante sui mock:

  • se helper A ha chiamato helper B
  • se service C ha chiamato serializer D
  • se una funzione interna privata è stata eseguita due volte

Obiettivo migliore:

  • Sapere cosa il funzionale ha restituito
  • Sapere se ha gestito una dipendenza fallita correttamente
  • Sapere se ha trasformato i dati nella forma attesa

Un miglior modello per Capacitor e Electron code

In app mobili e desktop, preferisco un layer di avvolgimento intorno alle API native o di piattaforma. Poi i test unitari simulano il layer di avvolgimento, non la piattaforma stessa.

Esempio di struttura:

// 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 });
});

Quel modello funziona anche per Electron. Avvolgere ipcRenderer, l'accesso ai file o le integrazioni della shell dietro un adattatore sottile. I test unitari colpiscono il layer di servizio, non la runtime direttamente.

Per le squadre che testano la logica di rilascio e le vie di aggiornamento negli app Capacitor, Capgo ha una guida rilevante su testare gli aggiornamenti OTA Capacitor con scenari di simulazione.

Un breve walkthrough aiuta se la tua squadra sta ancora normalizzando lo stile di test asincrono:

Testare flussi asincroni senza instabilità

Usa async/await in test quando il code in esame restituisce una promessa. È più chiaro dei pattern pesanti per callback e più facile da debuggare.

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');
});

Testa anche il percorso di fallimento:

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');
});

Testa sia il percorso felice che quello brutto. In produzione, il percorso brutto è quello che gli utenti ricordano.

Strategie Avanzate per Test Robusti

Un suite di test diventa utile quando rimane utile anche dopo che il code è cambiato. È più difficile di quanto sembri scrivere un mucchio di test che passano.

Un diagramma che illustra strategie per costruire software robusto attraverso una copertura di test completa e suite di test mantenibili.

Usa il testing split come un budget

Una guida pratica raccomanda di 70/20/10 dividere in test unitari, di integrazione e di fine-all'utentecon unit test, che forniscono il feedback più rapido e le fallite più stabili. Lo stesso consiglio afferma che un completo insieme di unit test dovrebbe ideale finire in meno di 10 secondie le verifiche pre-commit dovrebbero rimanere meno di 5 secondisecondo questo guida di testing di OpenReplay.

Tratto questo come uno strumento di budgeting, non come una religione. Se la maggior parte del tuo sforzo va nelle test end-to-end, il tuo team attenderebbe troppo a lungo per il feedback. Se tutto è unit-only, perderai i reali confini del sistema.

Per un'applicazione Capacitor o Electron, un equilibrio sano solitamente assomiglia a questo:

  • Unit test per la logica dei prezzi, le regole delle autorizzazioni, la serializzazione, l'aggiornamento dell'eligibilità, le bandiere delle funzionalità e le trasformazioni di stato
  • Test di integrazione per gli adattatori di archiviazione, le coperture dei plugin e i contratti IPC
  • E2E test per alcuni viaggi critici come l'accesso, il flusso di acquisto, la sincronizzazione o le richieste di aggiornamento

La copertura è una torcia, non un obiettivo

Le relazioni di copertura sono utili quando aiutano a individuare rami non testati in logiche importanti. Diventano dannose quando gli squadre inseguiamo percentuali di copertura per il loro proprio interesse.

A login validator with thoughtful edge-case tests gives more value than a covered file full of trivial assertions. That’s especially true for input-heavy code such as forms, parsers, date logic, and permission checks. If your team is tightening quality around validation-heavy UI, this guide on l'ottenimento della validazione dei form frontend è un buon complemento alla strategia di testing a livello di unità.

Test di comportamento che sopravvivono ai refactoring

Un insieme affidabile dovrebbe consentire di rifare gli interni senza dover ricompilare metà dei test. La via più facile per raggiungere questo è di affermare il comportamento osservabile piuttosto che i dettagli di implementazione.

Usi che mantengono bene la loro validità:

  • Condizioni di confine come input vuoti, valori nulli, tipi invalidi e stringhe sovrane
  • Esiti del dominio ad esempio “ritorni negati per mancanza di autorizzazione”
  • Transizioni di stato ad esempio “marca l'aggiornamento come in sospeso dopo la validazione dei metadati di download”

Usi che spesso si deteriorano:

  • individuare chiamate di aiuto interne
  • affermare la sequenza dei metodi privati
  • mockare ogni livello della catena di chiamata

Per le squadre di app che costruiscono processi di rilascio disciplinati, l'articolo di Capgo su la garanzia della qualità dell'app è utile perché collega il lavoro di testing al pipeline di rilascio più ampio.

Testing per CI, Capacitor, e App di Electron

Un test che esegue solo su una macchina del singolo sviluppatore non è un sistema di sicurezza. È un'abitudine locale.

CI trasforma il lavoro di testing JavaScript in infrastruttura di squadra. Ogni push, richiesta di pull o branch di rilascio può esercitare le stesse comandi con le stesse aspettative. Questa consistenza è ancora più importante per Capacitor e progetti di Electron, dove il drift dell'ambiente causa fallimenti sottili.

Fate del CI il percorso di esecuzione predefinito

Almeno, il vostro CI dovrebbe installare le dipendenze e eseguire il set di unit test su ogni set di modifiche. Mantenete il comando identico al possibile rispetto allo sviluppo locale.

Un workflow di GitHub Actions base può essere così piccolo:

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

È sufficiente per catturare importazioni rotte, affermazioni fallite e assunzioni di piattaforma accidentali prima che arrivino in main.

Per le squadre mobili che distribuiscono attraverso pipeline automatizzate, Capgo ha una guida pratica per l'impostazione di CI/CD per le app Capacitor.

Testing le interazioni del plugin Capacitor

L'errore di testing unitario Capacitor code è di estrarre i plugin nativi direttamente in ogni servizio. Ciò accoppia il vostro set di test al ponte di piattaforma.

La migliore strategia è un'astrazione sottile:

// 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 });
});

La stessa idea si applica all'accesso alla fotocamera, alle richieste di rilevamento biometrico, alla registrazione del token di push e allo stato della rete. Mantenere le chiamate ai plugin negli adapter. Testare la logica dell'applicazione contro gli interfacce che si controllano.

Testare Electron main renderer e IPC code

Gli app di Electron hanno due importanti giunture: processo principale code e processo di rendering code. Non confonderle nei test.

Un setup affidabile separa spesso:

  • Test di unità del renderer per i modelli di visualizzazione, lo stato, la formattazione e la logica commerciale del lato UI
  • Test di unità del processo principale per menu, operazioni sui file e decisioni sul ciclo di vita dell'applicazione
  • test del contratto di comunicazione IPC per la forma dei messaggi e le risposte previste

Esempio di 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' });
});

Se in seguito cambierai l'implementazione interna da un helper all'altro, questo test ancora funziona perché verifica il comportamento che conta. Quello è lo standard che desideri per desktop e mobile code.

Domande Frequenti sul Testing Unitario di JavaScript

Cosa differenzia i test di unità, integrazione e E2E

A test di unità controlla una piccola parte di logica in isolamento. Un test di integrazione controlla se alcuni componenti o servizi funzionano insieme correttamente. Un test di fine a fine simula un percorso dell'utente attraverso l'applicazione in esecuzione.

Usa i test unitari per una fiducia veloce nelle regole commerciali. Usa i test di integrazione per le giunzioni come la memorizzazione, le coperture di plugin e l'IPC. Usa i test E2E con parsimonia per i flussi di lavoro che si sarebbero seriamente danneggiati se si fossero rotti.

Dovremmo mirare a una copertura completa?

No. Una copertura completa può spingere i team verso test di basso valore.

La copertura è utile quando rivela rischi code che nessuno ha esercitato. Non è utile quando gli ingegneri aggiungono affermazioni superficiali solo per soddisfare un dashboard. Se il suo set di test è fragile, più copertura non lo salverà.

Come aggiungere test a un codicebase esistente?

Inizia dove le modifiche accadono già. Non fermare il team e annunciare una grande riscrittura della strategia dei test.

Una sequenza pratica assomiglia a questo:

  • Proteggi prima le code attive aggiungendo test ai moduli che toccate durante il lavoro di feature o i bug fix
  • Estrai la logica pura da file hard-to-test per cui le regole di business possono essere testate senza rumore di framework o runtime
  • Aggiungi involucri di interfaccia intorno ai plugin nativi, ai client di rete, alle chiamate al filesystem e alle comunicazioni IPC di Electron
  • Rifiuta modelli fragili quando si introducono mock. La guida dalle migliori pratiche di testing di JavaScript è particolarmente utile qui perché evidenzia il problema spesso trascurato dell'eccessiva simulazione e dei test fragili che ne derivano L'obiettivo non è la completezza immediata. È un miglioramento costante nei luoghi in cui le regressioni costano di più al team

Se il tuo team rilascia


Capacitor Live Update Capacitor Capacitor Live Update Electron applicazioni e richiede un processo di rilascio più pulito per le modifiche al JavaScript, Capgo è una delle opzioni da considerare. Fornisce aggiornamenti in tempo reale per le applicazioni CapacitorJS e Electron, con controlli di rollout e visibilità, quindi le squadre possono associare test di unità solide a un percorso più sicuro per la spedizione delle modifiche ai bundle web senza dover attendere la revisione del negozio per ogni correzione.

Aggiornamenti in tempo reale per le app Capacitor

When a web-layer bug is live, ship the fix through Capgo instead of waiting days for app store approval. Users get the update in the background while native changes stay in the normal review path.

Quando un bug nel layer web è attivo, invia la correzione attraverso __CAPGO_KEEP_0__ invece di aspettare giorni per l'approvazione della store. Gli utenti ricevono l'aggiornamento in background mentre le modifiche native rimangono nel normale percorso di revisione. Contesto: Pagina/area: Sito web di marketing Capgo. Ruolo: Descrizione di supporto o meta descrizione. Visibile in: componente GetStarted.astro. Preservare i termini di prodotto e marchio Capgo esattamente. Chiave del messaggio `aggiornamenti_instantanei_per_applicazioni_capacitor_descrizione` (Aggiornamenti Instantanei Per Applicazioni Capacitor Descrizione).

Avvia Ora

Ultimi articoli dal nostro Blog

Capgo vi offre le migliori informazioni che avete bisogno per creare un'app mobile davvero professionale.