Salta al contenuto principale

Unit Tests JavaScript: Guida completa 2026

Impara a gestire i test unitari con il nostro manuale 2026. Copre Jest, Mocha, configurazione, simulazione, CI e consigli per l'applicazione Capacitor e Electron.

Unit Tests JavaScript: Guida Completa 2026

Probabilmente ti trovi in una delle due situazioni. O il tuo progetto JavaScript ha quasi nessun test e ogni refactor sembra rischioso, o già hai test e la metà di loro sono lente, fragili e difficili da fidarsi.

Che peggiora in Capacitor Elettronica Electron I buoni test di unità JavaScript non iniziano con la sintassi dei matcher astuti. Inizia con un confine disciplinato: testa la logica pura direttamente, isolare gli effetti collaterali e evita di scrivere test che si sbriciolino non appena rinomini una funzione interna.

Good unit tests JavaScript work doesn’t start with clever matcher syntax. It starts with a disciplined boundary: test pure logic directly, isolate side effects, and avoid writing tests that collapse the moment you rename an internal function.

Scegliere il tuo framework di testing JavaScript

Scegliere il tuo framework di testing JavaScript

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

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

Un diagramma di confronto delle principali librerie di testing JavaScript, tra cui Jest, Mocha, Cypress e Playwright.

Perché un framework non è facoltativo

La prima cosa che le squadre fanno è trattare i test unitari come un'attività secondaria. Di solito porta a nomi di file inconsistenti, affermazioni personalizzate che nessuno ricorda e aiuti che solo una persona capisce.

Un framework ti dà un linguaggio condiviso:

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

Se il tuo team ha anche bisogno di una visione più ampia dell'automazione dei test al di là del lavoro a livello di unità, Capgo offre una panoramica utile l'automazione dei test nei 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. Consegna la maggior parte di ciò che le squadre hanno bisogno già al primo giorno.
Mocha è più modulare. Consegna un esecutore e si aspetta che tu assembli il resto della pila.

Caratteristica Jest Mocha
Complessità di configurazione Per la maggior parte delle squadre Più alta perché di solito aggiungi librerie di affermazione e simulazione
Affermazioni Costruito in Solitamente associato ad un'altra libreria
Mocking Costruito in Solitamente associato ad un'altra libreria
Test di asincronia Costruito in e diretto Sostenuto, ma dipende di più dalla configurazione circostante
Ciclo di copertura Comunemente integrato nello stesso toolchain Spesso più frammentato
Scelta migliore Nuovi progetti, team che desiderano coerenza Stack legacy, team che desiderano controllo modulare

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

Cosa consiglio per la maggior parte dei team

Per la maggior parte dei progetti moderni, sceglierei Jest se non ci sono forti motivi per mantenere Mocha. Questa raccomandazione diventa più forte quando l'applicazione include Capacitor or ElettronicaPerché questi progetti già hanno abbastanza componenti in movimento. Ridurre la dispersione di strumenti di testing si ripaga velocemente.

La Mocha ha ancora senso nei servizi Node.js più vecchi o nelle codebase a lungo termine dove l'ecosistema che la circonda è già stabilito. Ma per un ingegnere di livello medio che sta impostando un robusto set di test da zero, Jest rimuove di solito più frizione di quella che crea.

Nota importante di campo. Cypress e Playwright sono eccellenti strumenti, ma risolvono un problema diverso. Sono meglio per i controlli di browser e di fine-di-corsia, non per il rapido ciclo interno dove i test di unità dovrebbero vivere.

Configurazione del Progetto e Primo Test

Un setup di testing pulito dovrebbe essere noioso. Se l'aggiunta del primo test sembra complicata, il set di test probabilmente non resterà sano.

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

Una configurazione Jest semplice

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

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

Basta così per molti progetti. Puoi aggiungere ulteriore configurazione in seguito se il tuo sistema di moduli, la transpilazione o la struttura di monorepo lo richiedono.

Se stai costruendo un'app locale con Capacitor e vuoi avere il tuo ambiente di sviluppo in ordine prima di aggiungere i test intorno alla logica condivisa, il tuo guida di Capgo impostazione di un ambiente locale Capacitor è un compagno di studio pratico.

Scrivi il test prima del code

Non è solo una questione di preferenza personale. La guida JavaScript della Consumer Financial Protection Bureau degli Stati Uniti raccomanda esplicitamente di scrivere il test prima, organizzare i test con describe e it, e definire i controlli intorno expect(...) alle affermazioni nella sua guida di testing unitario JavaScript.

Questo conta 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 minimale:

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

Usa Arrange Act Assert ogni volta

Questo Disporre, Eseguire, Asserire il pattern mantiene i testi leggibili, anche quando crescono di complessità.

  1. Disporre l'input e qualsiasi configurazione necessaria.
  2. Eseguire chiamando la funzione.
  3. Asserire sull'esito.

Applicato a un aiutante 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);
  });
});

I testi piccoli durano bene. Un test dovrebbe di solito rispondere a una sola domanda, non descrivere un intero workflow.

Per i progetti Capacitor e Electron, quella disciplina conta di più perché la tua logica pura spesso si trova accanto all'integrazione nativa o desktopica code. Mantieni la regola di affari testabile senza il runtime della piattaforma, e il tuo primo test non sarà l'ultimo utile.

Maestri di Mock e Asincrono Code

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

Quello è dove l'inganno aiuta. Gli dà il controllo sul confine in modo che il test possa concentrarsi sulla decisione di code.

Un diagramma di whiteboard che illustra un'architettura a microservizi con API, archivi dati, servizi esterni e flusso dati basato su eventi.

Mockare i confini, non tutto

Linee guida per testi mantenibili enfatizzano la copertura del comportamento singolo e Una forte asserzione per teste avverte inoltre che l'uso eccessivo dei mock rende i test fragili e fortemente legati ai dettagli di implementazione, come riassunto in questo Articolo di TestRail sui test unitari mantenibili.

That warning matters a lot in JavaScript. Teams often start by mocking every imported module and end up testing whether functions call other functions in the “correct” order, instead of testing real behavior.

Bad target for a mock-heavy test:

  • se l'aiuto A ha chiamato l'aiuto B
  • se il servizio C ha chiamato il serializzatore D
  • se una funzione interna privata è stata eseguita due volte

Obiettivo migliore:

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

Un modello migliore 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 ipcRendererAccesso ai file o integrazioni shell tramite un adattatore sottile. I test unitari colpiscono il layer di servizio, non il runtime direttamente.

Per le squadre che testano la logica di rilascio e le vie di aggiornamento nei Capacitor app, Capgo ha una guida rilevante su testing Capacitor OTA updates with mock scenarios.

Un breve tour guidato può essere utile se il tuo team sta ancora normalizzando lo stile di test asincrono.

Eseguire flussi asincroni senza instabilità

Use async/await in test quando il code in esame restituisce una promessa. È più chiaro dei pattern pesanti di 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');
});

Anche testa 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 sgradevole. In produzione, il percorso sgradevole è spesso quello che gli utenti ricordano.

Strategie Avanzate per Test Robusti

Una suite di test diventa utile quando rimane utile anche dopo i cambiamenti code. È più difficile di scrivere una pila di test che passano.

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

Utilizza lo split di testing come un budget

Una guida pratica raccomanda un 70/20/10 diviso in test di unità, integrazione e fine a finecon unit test, che fornisce il feedback più rapido e le fallite più stabili. La stessa guida afferma che un insieme di unit test completo dovrebbe ideale finire in meno di 10 secondi, e le verifiche pre-commit dovrebbero rimanere meno di 5 secondi, secondo questa guida di testing di OpenReplay.

Considero questo come uno strumento di budgeting, non una religione. Se la maggior parte del tuo sforzo va ai test di fine a fine, il tuo team aspetterà troppo a lungo per il feedback. Se tutto è unitario, perderai i reali confini del sistema.

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

  • Test di unità per logica di prezzo, regole di autorizzazione, serializzazione, eleggibilità all'aggiornamento, flag di feature e trasformazioni di stato
  • Test di integrazione per adattatori di archiviazione, involucri di plugin e contratti di IPC
  • Test E2E 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 perseguono 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'arte della validazione dei form frontend è un buon complemento alla strategia di testing a livello di unità.

Test di comportamento sopravvivono ai refactoring

Un insieme affidabile dovrebbe consentire di rifare gli interni senza dover ricompilare metà dei test. La via più facile per raggiungerci è affermare comportamento osservabile al posto di dettagli di implementazione.

Casi d'uso che mantengono bene:

  • Condizioni di confine come input vuoto, valori nulli, tipi invalidi, e stringhe sovrastanti
  • Esiti del dominio come “ritornano negati per mancanza di autorizzazione”
  • Transizioni di stato come “marca aggiornamento come in sospeso dopo il download dei metadati è stato validato”

Casi d'uso che spesso marciscono:

  • ispezionare chiamate di aiuto interne
  • asserire sequenziamento di metodi privati
  • mockare ogni layer nella catena di chiamata

Per teami di app che costruiscono processi di rilascio disciplinati, l'articolo di Capgo 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 Electron

Una prova che si esegue solo su una macchina di un singolo sviluppatore non è un riparo. È un'abitudine locale.

CI trasforma il lavoro di testing unitario 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 i progetti Capacitor e Electron, dove il drift dell'ambiente causa fallimenti sottili.

Fate di CI la via di esecuzione predefinita

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

Un flusso di lavoro 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 inviano attraverso pipeline automatizzate, Capgo ha una guida pratica a impostazione della CI/CD per le Capacitor app.

Test delle interazioni del plugin Capacitor

La maniera sbagliata di testare le unità di Capacitor code è di estrarre i plugin nativi direttamente in ogni servizio. Ciò lega il tuo set di test alla piattaforma di bridge.

La migliore strategia è una sottile astrazione:

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

L'idea è applicabile anche all'accesso alla camera, alle richieste di rilevamento biometrico, alla registrazione del token di push e allo stato della rete. Mantieni le chiamate ai plugin nelle adapter. Testa la logica dell'app contro gli interfacce che controlli.

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 rendering unit Per modelli di vista, stato, formattazione e logica commerciale per l'interfaccia utente
  • Test di processo principale unit Per menu, operazioni sui file e decisioni sul ciclo di vita dell'app.
  • Test del contratto IPC per forma dei messaggi e 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 tiene 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 Unità di test verifica una piccola porzione di logica in isolamento. Un test di integrazione verifica se alcuni componenti o servizi funzionano correttamente insieme. Un test end-to-end esercita 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 archiviazione, wrapper dei plugin e 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. La 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, una copertura maggiore non lo salverà.

Come aggiungere test a un codicebase esistente

Inizia dove le modifiche avvengono già. Non fermare l'intero team e annunciare una grande riscrittura della strategia dei test.

Una sequenza pratica assomiglia a questo:

  • Proteggi attivamente code in primo luogo Aggiungendo test a moduli che toccate durante il lavoro di feature o i bug fix
  • Estrai logica pura da file di difficile test so le regole di affari possono essere testate senza rumore del framework o del runtime
  • Aggiungi rivestimenti di fessura intorno a plugin nativi, client di rete, chiamate al filesystem e IPC di Electron
  • Rifiuta modelli fragili quando si introduce le mock. Buone pratiche di testing per JavaScript L'obiettivo non è la completezza immediata. È un miglioramento costante nei luoghi dove le regressioni costano più al team

L'obiettivo non è la completezza immediata. È un miglioramento costante nei luoghi dove le regressioni costano di più al team.


Se il tuo team rilascia Capacitor o Electron applicazioni e richiede un processo di rilascio più pulito per le modifiche al JavaScript. Capgo is one option to look at. It provides live updates for CapacitorJS and Electron apps, with rollout controls and observability, so teams can pair solid unit testing with a safer path to shipping web bundle changes without waiting on store review for every fix.

Aggiornamenti in tempo reale per le Capacitor app

When a bug nel layer web è attivo, invia la correzione attraverso Capgo invece di attendere giorni per l'approvazione della store. Gli utenti ricevono l'aggiornamento in background mentre le modifiche native rimangono nel normale percorso di revisione.

Supporto umano da Martin

Inizia subito

Ultimi articoli dal nostro Blog

Capgo ti offre le migliori informazioni che ti servono per creare un'app mobile davvero professionale.