Saltare al contenuto principale

Unit Tests JavaScript: Guida completa 2026

Esegui test unitari javascript con la nostra guida del 2026. Copre Jest, Mocha, configurazione, simulazione, CI e consigli per Capacitor & applicazioni Electron.

Test Unitari JavaScript: Guida Completa 2026

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

Si aggravano in Capacitor e Electron Buoni test unitari JavaScript non iniziano con sintassi di matcher astuta. Iniziano con un confine disciplinato: testate la logica pura direttamente, isolate gli effetti collaterali e evitate di scrivere test che si dissolvono non appena rinominiate 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.

Indice dei contenuti

Scegliere il tuo framework di testing JavaScript

Un progetto JavaScript professionale ha bisogno di un vero e proprio esecutore di test. I 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, il trattamento degli async, i mock e un modo per eseguire tutto in modo coerente nel development locale e CI.

Il consiglio attuale converge sempre su una piccola serie di opzioni mainstream. Jest, Mocha e Jasmine sono ripetutamente evidenziati come le principali librerie, con Jest spesso isolato per la struttura dei test integrata, le affermazioni, i mock e il supporto async in un unico pacchetto, come mostrato in questo lab di testing JavaScript di Pluralsight.

Un diagramma di confronto delle librerie di testing JavaScript popolari, comprese 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. Ciò porta spesso a nomi di file non coerenti, affermazioni personalizzate che nessuno ricorda e aiuti che solo una persona comprende.

A un framework ti offre un linguaggio condiviso:

  • Struttura dei test con describe e test o it
  • Assert con matcher leggibili
  • Hook per l'installazione e la rimozione
  • Sostegno asincrono per promesse e timer
  • Strumenti di mockaggio 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 automated testing in app delivery workflows.

Jest vs Mocha in una sola occhiata

Jest e Mocha rappresentano due filosofie diverse.

Jest è l'opzione tuttofare. Spedisce la maggior parte di ciò che le squadre hanno bisogno già dal primo giorno.
Mocha è più modulare. Viene fornito con un esecutore e si aspetta che voi assembliate il resto della pila.

Funzione Jest Mocha
Complessità di setup Meno per la maggior parte delle squadre Più alta perché di solito aggiungi librerie di assert e mocking
Assert Integrato Di solito associato a un'altra libreria
Mocking Integrato Di solito associato a un'altra libreria
Test asincroni Costruito in modo diretto e semplice Sostenuto, ma dipende di più dalla configurazione circostante
Flusso di copertura Comunemente integrato nello stesso catena di tool Spesso più pezzi messi insieme
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 assert e quale libreria di mocking 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 mantenere Mocha nel codice esistente. Questa raccomandazione diventa più forte quando l'applicazione include Capacitor o Elettronica, perché questi progetti hanno già abbastanza parti in movimento. Ridurre la dispersione di strumenti di testing si ripaga velocemente.

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

Un importante nota di campo. Cypress e Playwright sono eccellenti strumenti, ma risolvono un problema diverso. Sono meglio per i controlli a livello di browser e end-to-end, non per il rapido ciclo interno dove i test di unità dovrebbero vivere.

Configurazione del Progetto e il Primo Test

Un setup di testing pulito dovrebbe essere noioso. Se aggiungere il primo test sembra complicato, 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 semplice configurazione di Jest

Inizia con un progetto JavaScript che già ha un package.jsonPoi aggiungi 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 Capacitor localmente e vuoi che il tuo ambiente di sviluppo sia in ordine prima di aggiungere test intorno alla logica condivisa, il Capgo's guida per l'impostazione di un ambiente locale Capacitor Scrivi il test prima del __CAPGO_KEEP_0__

Write the test before the code

Il pattern test-first non è solo una questione di preferenza personale. La guida JavaScript della Consumer Financial Protection Bureau degli Stati Uniti raccomanda esplicitamente , organizzare i test conorganizzare i test con describe and italle affermazioni nella sua expect(...) guida di testing unitario JavaScript Guida allo testing unitario del JavaScript.

Perché conta i test prima, perché cambia il modo in cui progettate 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);
  });
});

Usate Arrange Act Assert ogni volta

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

  1. Preparare l'input e qualsiasi setup necessario.
  2. Agire chiamando la funzione.
  3. Affermare su il 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);
  });
});

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 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. Gli dà il controllo sul confine affinché la prova possa concentrarsi sulla decisione di code.

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

Mockare i confini, non tutto

La guida per le prove sostenibili enfatizza copertura di comportamento singolo e Una forte affermazione per test, e inoltre avverte che l'uso eccessivo dei mock rende i testi fragili e strettamente legati ai dettagli di implementazione, come riassunto in questo articolo di TestRail sui test unitari mantenibili.

Quel warning 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

Obiettivo sbagliato per un test pesante con mock:

  • invece di testare il comportamento reale.
  • se il servizio C chiama il serializzatore D
  • se un metodo interno privato è stato eseguito due volte

Obiettivo migliore:

  • il valore di ritorno della funzione
  • se gestisce correttamente una dipendenza fallita
  • se è stata trasformata la data nella forma attesa

Un modello migliore per Capacitor e Electron code

In applicazioni 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.

Struttura di esempio:

// 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 pattern funziona anche per Electron. Avvolgi 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 testare gli aggiornamenti Capacitor OTA 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 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 la via del 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 la via felice che la via brutta. In produzione, la via brutta è quella che gli utenti ricordano di più.

Strategie Avanzate per Test Robusti

Un insieme di test diventa utile quando rimane utile anche dopo i code cambiamenti. È più difficile 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.

Usa lo split di testing come budget

Una guida pratica raccomanda una 70/20/10 split tra test unitari, test di integrazione e test end-to-endcon unit test fornendo il feedback più rapido e le fallite più stabili. La stessa guida suggerisce che un completo suite di unit test dovrebbe ideale finire in meno di 10 secondi, e le verifiche pre-commit dovrebbero rimanere meno di 5 secondi, secondo questo Guida di testing di OpenReplay.

Considero questo come uno strumento di budgeting, non una religione. Se la maggior parte del tuo sforzo va a testare i casi di fine-utente, il tuo team dovrà attendere troppo a lungo per ricevere 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à dell'aggiornamento, flag di feature e trasformazioni di stato
  • Test di integrazione per gli adapter di archiviazione, i wrapper dei plugin e i contratti IPC
  • E2E tests 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 i team perseguono percentuali di copertura per il loro proprio interesse.

Un validatore di accesso con test di edge-case pensati dà più valore di un file coperto pieno di affermazioni triviali. È vero soprattutto per gli input pesanti code come form, parser, logica delle date e controlli delle autorizzazioni. Se il tuo team sta stringendo la qualità intorno alla UI con validazione pesante, questo guida su validazione dei form frontend è una buona integrazione alla strategia di testing a livello di unità.

Le test di comportamento sopravvivono ai refactoring

Una suite affidabile dovrebbe consentirti 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:

  • Condizioni di confine come input vuoti, valori nulli, tipi non validi e stringhe troppo grandi
  • Esiti del dominio come “ritornano negati per mancanza di autorizzazione”
  • Transizioni di stato come ad esempio "marca l'aggiornamento come in attesa dopo la validazione dei metadati del download"

I casi d'uso che spesso si deteriorano:

  • l'ispezione delle chiamate di aiuto interne
  • l'affermazione della sequenza dei metodi privati
  • l'inganno di ogni livello nella catena di chiamata

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

Testing per CI, Capacitor, e applicazioni 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 istruzioni con le stesse aspettative. Quella consistenza conta ancora di più per Capacitor e progetti Electron, dove il drift dell'ambiente causa fallimenti sottili.

Rendere CI il percorso di esecuzione predefinito

At minimum, il tuo CI dovrebbe installare le dipendenze e eseguire il set di unit test su ogni set di modifiche. Mantieni il comando identico a quello di sviluppo locale quando possibile.

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

Questo è 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 per l'impostazione di CI/CD per le app Capacitor.

La prova di interazione del plugin Capacitor

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

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

L'idea è la stessa per l'accesso alla fotocamera, le richieste di biometria, la registrazione dei token di push e lo stato della rete. Mantieni le chiamate ai plugin nelle adattatori. Prova la logica dell'app contro gli interfacce che controlli.

Testare Electron main renderer e IPC code

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

Una configurazione affidabile separa generalmente:

  • Test di rendering unitari Per modelli di vista, stato, formattazione e logica commerciale per l'interfaccia utente
  • Test delle unità del processo principale per menu, operazioni sui file e decisioni sul ciclo di vita dell'app.
  • Test del contratto 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 rimane valido perché verifica il comportamento che conta. Quello è lo standard che desideri per desktop e mobile code.

Frequenti domande sulle prove di unità JavaScript

Cosa differenzia le prove di unità da quelle di integrazione e E2E

A prova di unità controlla una piccola porzione di logica in isolamento. Una prova di integrazione controlla se alcuni componenti o servizi funzionano correttamente insieme. Una test di integrazione esercita un percorso di utilizzo attraverso l'applicazione in esecuzione.

Usa le prove di unità per una rapida conferma delle regole commerciali. Usa le prove di integrazione per le giunzioni come archiviazione, wrapper dei plugin e IPC. Usa le prove E2E con parsimonia per i flussi di lavoro che si sarebbero seriamente danneggiati se si fossero rotte.

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, più copertura non lo salverà.

Come aggiungere test a un codice esistente

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

Una sequenza pratica assomiglia a questo:

  • Protetti attivi code per primi Aggiungendo test ai moduli che si toccano durante il lavoro di feature o i bug fix
  • Estrai logica pura da file difficili da testare in modo che le regole di affari possano essere testate senza rumore del framework o runtime
  • Aggiungi rivestimenti di fessura intorno a plugin nativi, client di rete, chiamate al filesystem e IPC di Electron
  • Rifiuta modelli fragili quando si introducono mock. Guida da Pratiche di testing JavaScript è particolarmente utile qui perché evidenzia il problema spesso trascurato dell'eccessiva mockatura e dei test fragili che ne derivano

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


Se il tuo team rilascia Capacitor or Electron Applicazioni e richiede un processo di rilascio più pulito per le modifiche 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 app Capacitor

Quando un bug nel layer web è attivo, invia la correzione attraverso Capgo 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.

Ultimi dalla nostra Blog

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