🌐 Detecting your location…
📢 Advertisement — Configure AdSense in Appearance → Customize → AdSense Settings

So schreiben Sie Integrationstests für eine REST-API im Jahr 2026: Vollständiger Leitfaden

⏱️5 min read  ·  983 words

Integrationstests Überprüfen Sie, ob die Teile Ihrer API – Routen, Datenbank und Geschäftslogik – korrekt zusammenarbeiten, indem Sie echte Anfragen stellen und echte Antworten überprüfen. Im Gegensatz zu Unit-Tests (die alles verspotten) fangen Integrationstests Fehler an den Grenzen auf. Diese Anleitung zeigt, wie man sie gut schreibt.

Unit- und Integrationstests

Aspekt Unit-Test Integrationstest
Geltungsbereich Eine Funktion isoliert Mehrere Teile zusammen (Strecke + DB)
Abhängigkeiten Verspottet Echte (oder Test-)Datenbank
Geschwindigkeit Sehr schnell Langsamer (echte E/A)
Fänge Logikfehler Integrations-/Verkabelungsfehler

Sie wollen beides – Unit-Tests für die Logik, Integrationstests, um zu überprüfen, ob der gesamte Anfrage-Antwort-Fluss funktioniert.

Node.js: Testen mit Supertest

npm install --save-dev jest supertest
// Export your app WITHOUT calling listen() so tests can use it
// app.js
const express = require('express');
const app = express();
app.use(express.json());
app.get('/users/:id', getUser);
app.post('/users', createUser);
module.exports = app;   // export the app

// server.js (separate) starts it
const app = require('./app');
app.listen(3000);
// users.test.js
const request = require('supertest');
const app = require('./app');
const db = require('./db');

describe('Users API', () => {
  beforeEach(async () => {
    await db.reset();   // clean database before each test
  });

  afterAll(async () => {
    await db.close();
  });

  it('creates a user', async () => {
    const res = await request(app)
      .post('/users')
      .send({ name: 'Alice', email: 'alice@example.com' });

    expect(res.status).toBe(201);
    expect(res.body).toMatchObject({ name: 'Alice' });
    expect(res.body.id).toBeDefined();
  });

  it('returns 404 for missing user', async () => {
    const res = await request(app).get('/users/999');
    expect(res.status).toBe(404);
  });

  it('validates required fields', async () => {
    const res = await request(app).post('/users').send({});
    expect(res.status).toBe(400);
    expect(res.body.error).toBeDefined();
  });
});

Python: Testen mit pytest und TestClient

pip install pytest httpx
# test_users.py (FastAPI example)
import pytest
from fastapi.testclient import TestClient
from app.main import app
from app.database import get_test_db

client = TestClient(app)

@pytest.fixture(autouse=True)
def reset_db():
    db = get_test_db()
    db.reset()
    yield
    db.close()

def test_create_user():
    response = client.post("/users", json={
        "name": "Alice", "email": "alice@example.com"
    })
    assert response.status_code == 201
    data = response.json()
    assert data["name"] == "Alice"
    assert "id" in data

def test_get_missing_user():
    response = client.get("/users/999")
    assert response.status_code == 404

def test_validation_error():
    response = client.post("/users", json={})
    assert response.status_code == 422

Verwendung einer Testdatenbank

Integrationstests benötigen eine echte (Test-)Datenbank – getrennt von Entwicklung und Produktion:

# Spin up a test database with Docker
docker run -d --name test-db -p 5433:5432 \
  -e POSTGRES_DB=testdb -e POSTGRES_PASSWORD=test \
  postgres:15-alpine

# Point tests at it via environment
DATABASE_URL=postgresql://postgres:test@localhost:5433/testdb
// Fast reset using transactions (rollback after each test)
beforeEach(async () => {
  await db.query('BEGIN');
});
afterEach(async () => {
  await db.query('ROLLBACK');   // undo all changes — fast and clean
});

Authentifizierte Endpunkte testen

describe('Protected routes', () => {
  let token;

  beforeAll(async () => {
    const res = await request(app)
      .post('/login')
      .send({ email: 'test@example.com', password: 'password' });
    token = res.body.accessToken;
  });

  it('allows access with valid token', async () => {
    const res = await request(app)
      .get('/protected')
      .set('Authorization', `Bearer ${token}`);
    expect(res.status).toBe(200);
  });

  it('rejects without token', async () => {
    const res = await request(app).get('/protected');
    expect(res.status).toBe(401);
  });
});

Ausführen von Integrationstests in CI

# GitHub Actions with a service database
jobs:
  test:
    runs-on: ubuntu-latest
    services:
      postgres:
        image: postgres:15
        env:
          POSTGRES_DB: testdb
          POSTGRES_PASSWORD: test
        ports: ['5432:5432']
        options: --health-cmd pg_isready --health-interval 10s
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with: { node-version: '20' }
      - run: npm ci
      - run: npm run test:integration
        env:
          DATABASE_URL: postgresql://postgres:test@localhost:5432/testdb

Best Practices

  • Einzeltests: Jeder Test sollte unabhängig sein – setzen Sie die Datenbank zwischen den Tests zurück
  • Testen Sie den Vertrag: Statuscodes, Antwortform und Fehlerfälle überprüfen
  • Fehlerpfade abdecken: Testen Sie 400er, 401er, 404er und Validierungsfehler, nicht nur den glücklichen Weg
  • Verwenden Sie eine echte Testdatenbank: Verspotten Sie die Datenbank nicht in Integrationstests
  • Halten Sie sie einigermaßen schnell: Das Transaktions-Rollback ist schneller als das Abschneiden von Tabellen
  • In CI ausführen: Integrationstests fangen Verdrahtungsfehler auf, die Unit-Tests übersehen

Häufig gestellte Fragen

F: Sollte ich die Datenbank in Integrationstests verspotten?
A: Nein – es geht darum, echte Interaktionen, einschließlich der Datenbank, zu überprüfen. Verwenden Sie eine separate Testdatenbank. Wenn Sie es verspotten, wird es zu einem Unit-Test und übersieht die Integrationsfehler, die Sie abfangen möchten.

F: Wie halte ich Integrationstests schnell?
A: Verwenden Sie ein Transaktions-Rollback zwischen Tests, anstatt Tabellen abzuschneiden/neu zu erstellen. Führen Sie Tests parallel durch, sofern die Isolation dies zulässt. Verwenden Sie eine containerisierte Datenbank und halten Sie sie klein.

F: Wie viele Integrationstests benötige ich?
A: Decken Sie die kritischen Pfade jedes Endpunkts ab – Erfolg, Validierungsfehler, Authentifizierungsfehler und nicht gefundene Fälle. Unit-Tests behandeln Logikdetails; Integrationstests decken die Hauptverhaltensweisen jedes Endpunkts ab.

F: Integrationstests oder E2E-Tests?
A: Integrationstests überprüfen die API-Schicht (Routen + Datenbank). E2E-Tests überprüfen den vollständigen Benutzerfluss durch die Benutzeroberfläche. Beide haben ihren Wert – sie verfügen über mehr Integrationstests als E2E, da sie schneller und fokussierter sind.

F: Wie teste ich externe API-Aufrufe?
A: Verspotten Sie diese spezifischen Aufrufe (Sie möchten nicht, dass Tests Dienste Dritter betreffen), während Ihre Datenbank authentisch bleibt. Verspotten Sie nur echte externe Abhängigkeiten, nicht Ihre eigene Datenbank.

Fazit

Integrationstests überprüfen, ob Ihre API durchgängig funktioniert – Routen, Datenbank und Logik zusammen – und erkennen Verkabelungsfehler, die bei Unit-Tests übersehen werden. Verwenden SieSupertest mit Jest (Node.js) oder Pytest mit TestClient (Python), verweisen sie auf eine echte Testdatenbank (Zurücksetzen zwischen Tests über Transaktions-Rollback aus Geschwindigkeitsgründen) und decken Erfolgsfälle, Validierungsfehler, Authentifizierung und nicht gefundene Pfade ab. Führen Sie sie in CI mit einer Dienstdatenbank aus. In Kombination mit Unit-Tests für die Logik geben Ihnen Integrationstests die Gewissheit, dass Ihre API tatsächlich so funktioniert, wie Kunden es erwarten.

✍️ Leave a Comment

Your email address will not be published. Required fields are marked *

🌐 Read in:🇩🇪 Deutsch🇧🇷 Português🇸🇦 العربية🇮🇳 हिन्दी🇧🇩 বাংলা