Testen in JavaScript: Unit-, Integrations- und E2E-Tests auf fortgeschrittenem Niveau

Online Python-Trainer für Anfänger

Lernen Sie Python einfach ohne theoretische Überlastung. Lösen Sie praktische Aufgaben mit automatischer Überprüfung und schreiben Sie Code direkt im Browser.

Kurs starten

Einleitung: Warum fortgeschrittenes Testen ein Must-have für JavaScript-Projekte ist

In der modernen Entwicklung mit Node.js ist das Testen kein optionaler Schritt mehr. Ohne eine qualitativ hochwertige Testabdeckung wird jede Refaktorisierung oder das Hinzufügen neuer Funktionalität schnell zum "russischen Roulette". Es reicht jedoch nicht aus, einfach ein paar Asserts zu schreiben. Auf fortgeschrittenem Niveau muss ein Entwickler drei Hauptebenen beherrschen: Unit-Tests (Überprüfung isolierter Module), Integrationstests (Zusammenspiel von Komponenten, DB, API) und E2E-Tests (Simulation von Benutzeraktionen). In diesem Artikel werden wir praktische Techniken für jede Ebene am Beispiel von Node.js mit modernen Tools wie Jest, Supertest und Playwright behandeln.



1. Unit-Tests: Isolation, Mocks und Stubs auf fortgeschrittenem Niveau

Unit-Tests überprüfen die Arbeit einer einzelnen Funktion oder eines Moduls in Isolation von externen Abhängigkeiten (DB, Dateisystem, Netzwerkanfragen). Die Hauptaufgabe besteht darin, diese Abhängigkeiten korrekt zu mocken, damit der Test schnell und deterministisch ist.



Fortgeschrittene Mocking-Techniken in Jest

Betrachten wir ein Beispiel: Eine Funktion, die eine externe API aufruft und das Ergebnis in Redis zwischenspeichert. Wir müssen die Caching-Logik testen, ohne echte Anfragen durchzuführen.

// cacheService.jsconst axios = require('axios');const redis = require('redis');

class CacheService { constructor() { this.client = redis.createClient(); }

async fetchData(url) { const cached = await this.client.get(url); if (cached) return JSON.parse(cached);

const response = await axios.get(url); await this.client.setEx(url, 3600, JSON.stringify(response.data)); return response.data; }}

module.exports = CacheService;


// cacheService.test.jsconst CacheService = require('./cacheService');const axios = require('axios');const redis = require('redis');

jest.mock('axios');jest.mock('redis', () => ({ createClient: jest.fn(() => ({ get: jest.fn(), setEx: jest.fn() }))}));

describe('CacheService', () => { let service; let mockRedisClient;

beforeEach(() => { mockRedisClient = redis.createClient(); service = new CacheService(); });

test('should return cached data if present', async () => { const url = 'https://api.example.com/data'; const cachedData = { id: 1, value: 'cached' }; mockRedisClient.get.mockResolvedValue(JSON.stringify(cachedData));

const result = await service.fetchData(url);

expect(result).toEqual(cachedData); expect(axios.get).not.toHaveBeenCalled(); });

test('should fetch and cache data if not cached', async () => { const url = 'https://api.example.com/data'; const apiData = { id: 2, value: 'fresh' }; mockRedisClient.get.mockResolvedValue(null); axios.get.mockResolvedValue({ data: apiData });

const result = await service.fetchData(url);

expect(result).toEqual(apiData); expect(mockRedisClient.setEx).toHaveBeenCalledWith(url, 3600, JSON.stringify(apiData)); });});

Wichtige Punkte:

  • jest.mock('axios') mockt automatisch das gesamte axios-Modul.
  • Für Redis verwenden wir eine Factory, die einen Mock mit den Methoden get und setEx zurückgibt.
  • Wir überprüfen, dass bei vorhandenem Cache der externe Aufruf nicht erfolgt.


2. Integrationstests: Testen der Interaktion mit einer echten DB und API

Integrationstests überprüfen, wie verschiedene Teile des Systems zusammenarbeiten. Für Node.js bedeutet dies oft das Testen von Express-Routen mit einer echten (oder Test-)Datenbank. Das beste Tool ist Supertest in Kombination mit Jest.



Einrichtung einer Testdatenbank und Supertest

Beispiel: Eine API zur Benutzerverwaltung. Wir verwenden SQLite im Speicher zur Isolierung

Blogs

Buchempfehlungen