Hallo Welt
Hallo Welt
Original Lingva Deutsch
Übersetzung wird vorbereitet...
Dieser Vorgang kann bis zu 60 Sekunden dauern.
Diese Seite wird erstmalig übersetzt und dann für alle Besucher gespeichert.
0%
DE Zurück zu Deutsch
Übersetzung durch Lingva Translate

234 Dokumentationen verfügbar

Wissensdatenbank

Mocking Stubbing Testing

Zuletzt aktualisiert: 20.01.2026 um 10:03 Uhr

Mocking & Stubbing: Test-Doubles erklärt

Test-Doubles isolieren Code für besseres Testing. Lernen Sie den Unterschied zwischen Mocks, Stubs und Spies.

Die Test-Double Typen

Typ Beschreibung Verwendung
Stub Gibt vordefinierte Werte zurück Input für Code unter Test
Mock Prüft Erwartungen (Aufrufe) Verifizieren von Interaktionen
Spy Echte Implementierung + Tracking Aufrufe aufzeichnen
Fake Vereinfachte Implementierung In-Memory DB statt echter DB
Dummy Platzhalter, wird nicht verwendet Erfüllt Signatur

Stubs: Kontrollierte Rückgabewerte

// Jest (JavaScript)
const userRepository = {
    findById: jest.fn()
};

// Stub: Immer gleichen Wert zurückgeben
userRepository.findById.mockReturnValue({ id: 1, name: 'Max' });

// Stub: Promise zurückgeben
userRepository.findById.mockResolvedValue({ id: 1, name: 'Max' });

// Stub: Unterschiedliche Werte pro Aufruf
userRepository.findById
    .mockReturnValueOnce({ id: 1, name: 'Max' })
    .mockReturnValueOnce({ id: 2, name: 'Anna' })
    .mockReturnValue(null); // Für alle weiteren

// Stub: Basierend auf Argumenten
userRepository.findById.mockImplementation((id) => {
    if (id === 1) return { id: 1, name: 'Max' };
    if (id === 2) return { id: 2, name: 'Anna' };
    return null;
});

Mocks: Erwartungen prüfen

// Service der getestet wird
class NotificationService {
    constructor(emailClient) {
        this.emailClient = emailClient;
    }

    async notifyUser(user, message) {
        await this.emailClient.send(user.email, message);
    }
}

// Test mit Mock
describe('NotificationService', () => {
    test('sends email to user', async () => {
        // Mock erstellen
        const emailClient = {
            send: jest.fn().mockResolvedValue(true)
        };

        const service = new NotificationService(emailClient);
        const user = { email: 'test@example.com' };

        // Act
        await service.notifyUser(user, 'Hello!');

        // Assert: Mock-Erwartungen prüfen
        expect(emailClient.send).toHaveBeenCalled();
        expect(emailClient.send).toHaveBeenCalledTimes(1);
        expect(emailClient.send).toHaveBeenCalledWith('test@example.com', 'Hello!');
    });

    test('does not send if user has no email', async () => {
        const emailClient = { send: jest.fn() };
        const service = new NotificationService(emailClient);

        await service.notifyUser({ email: null }, 'Hello!');

        expect(emailClient.send).not.toHaveBeenCalled();
    });
});

Spies: Echte Implementierung tracken

// Spy auf echte Methode
const calculator = {
    add(a, b) {
        return a + b;
    }
};

const addSpy = jest.spyOn(calculator, 'add');

// Echte Implementierung wird ausgeführt
const result = calculator.add(2, 3); // = 5

// Aber wir können Aufrufe prüfen
expect(addSpy).toHaveBeenCalledWith(2, 3);

// Spy wieder entfernen
addSpy.mockRestore();

// Spy mit überschriebener Implementierung
jest.spyOn(calculator, 'add').mockReturnValue(100);
calculator.add(2, 3); // = 100

Module Mocking

// axios mocken
jest.mock('axios');
import axios from 'axios';

test('fetches users', async () => {
    axios.get.mockResolvedValue({
        data: [{ id: 1, name: 'Max' }]
    });

    const result = await fetchUsers();

    expect(axios.get).toHaveBeenCalledWith('/api/users');
    expect(result).toHaveLength(1);
});

// Partial Mock (nur bestimmte Funktionen)
jest.mock('./utils', () => ({
    ...jest.requireActual('./utils'),
    fetchData: jest.fn()
}));

// Auto-Mock zurücksetzen
beforeEach(() => {
    jest.clearAllMocks(); // Aufrufe zurücksetzen
    jest.resetAllMocks(); // + Implementierung zurücksetzen
});

PHP: Mocking mit PHPUnit

<?php
use PHPUnit\Framework\TestCase;

class OrderServiceTest extends TestCase
{
    public function test_creates_order_and_sends_notification(): void
    {
        // Mock erstellen
        $notificationService = $this->createMock(NotificationService::class);

        // Erwartung definieren
        $notificationService
            ->expects($this->once())
            ->method('send')
            ->with(
                $this->equalTo('user@example.com'),
                $this->stringContains('Order')
            );

        // Service unter Test
        $orderService = new OrderService($notificationService);
        $orderService->createOrder(['email' => 'user@example.com']);
    }

    public function test_returns_stubbed_value(): void
    {
        $repository = $this->createMock(UserRepository::class);

        // Stub: Rückgabewert definieren
        $repository
            ->method('findById')
            ->willReturn(new User(1, 'Max'));

        $service = new UserService($repository);
        $user = $service->getUser(1);

        $this->assertEquals('Max', $user->getName());
    }

    public function test_stub_with_callback(): void
    {
        $repository = $this->createMock(UserRepository::class);

        $repository
            ->method('findById')
            ->willReturnCallback(function ($id) {
                return $id === 1 ? new User(1, 'Max') : null;
            });
    }
}

Fakes: Vereinfachte Implementierungen

// Fake In-Memory Repository
class FakeUserRepository {
    constructor() {
        this.users = new Map();
        this.nextId = 1;
    }

    async create(data) {
        const user = { id: this.nextId++, ...data };
        this.users.set(user.id, user);
        return user;
    }

    async findById(id) {
        return this.users.get(id) || null;
    }

    async findAll() {
        return Array.from(this.users.values());
    }

    async delete(id) {
        return this.users.delete(id);
    }
}

// Im Test verwenden
test('user workflow', async () => {
    const repo = new FakeUserRepository();
    const service = new UserService(repo);

    const user = await service.createUser({ name: 'Max' });
    expect(user.id).toBe(1);

    const found = await service.getUser(1);
    expect(found.name).toBe('Max');
});

Best Practices

✅ Gutes Mocking:
  • Mocke externe Dependencies (APIs, DBs, File System)
  • Mocke nicht den Code der getestet wird
  • Vermeide zu viele Mocks in einem Test
  • Prüfe nur relevante Interaktionen
❌ Anti-Patterns:
  • Jede Methode mocken (Test ist zu gekoppelt)
  • Implementierungsdetails testen statt Verhalten
  • Mocks nicht zurücksetzen zwischen Tests

Weitere Informationen