tdd-strict

Erzwingt striktes Test-Driven Development mit Red-Green-Refactor Zyklus. Blockiert Code-Generierung ohne vorherige Tests. Dokumentiert 13 ungueltige Rationalisierungen. Aktivieren bei neuen Features, Bug Fixes, Refactoring.

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "tdd-strict" with this command: npx skills add svenja-dev/claude-code-skills/svenja-dev-claude-code-skills-tdd-strict

Striktes Test-Driven Development

Dieser Skill erzwingt TDD-Praktiken basierend auf dem Kernprinzip:

"If you didn't watch the test fail, you don't know if it tests the right thing."

Wann aktivieren

  • Bei jeder neuen Feature-Implementierung
  • Bei Bug Fixes (erst Test der Bug reproduziert, dann Fix)
  • Bei Refactoring (Tests muessen vor UND nach Aenderung bestehen)
  • Bei API-Erweiterungen
  • Bei jeder exportierten Funktion

Der Red-Green-Refactor Zyklus

1. RED: Test schreiben der fehlschlaegt

// ZUERST: Test schreiben
describe('calculateOEE', () => {
  it('should return 0 when availability is 0', () => {
    const result = calculateOEE({ availability: 0, performance: 100, quality: 100 });
    expect(result).toBe(0);
  });
});

// Test MUSS fehlschlagen:
// Error: calculateOEE is not defined
// ODER
// Error: Expected 0 but received undefined

Wichtig: Der Test MUSS aus dem richtigen Grund fehlschlagen:

  • Funktion existiert nicht
  • Funktion gibt falsches Ergebnis zurueck
  • NICHT: Syntaxfehler im Test selbst

2. GREEN: Minimaler Code der Test besteht

// DANACH: Minimaler Code
export function calculateOEE(params: OEEParams): number {
  if (params.availability === 0) return 0;
  // Weitere Logik kommt spaeter durch weitere Tests
  return 0;
}

Regel: Schreibe den EINFACHSTEN Code der den Test besteht.

  • Keine Optimierungen
  • Keine zusaetzlichen Features
  • Keine "offensichtlichen" Erweiterungen

3. REFACTOR: Bereinigen ohne neues Verhalten

// Nach mehreren gruenen Tests: Refactoring erlaubt
export function calculateOEE({ availability, performance, quality }: OEEParams): number {
  return (availability * performance * quality) / 10000;
}

Regeln fuer Refactoring:

  • Alle bestehenden Tests MUESSEN bestehen bleiben
  • KEIN neues Verhalten hinzufuegen
  • Nur Code-Struktur verbessern
  • Nach jedem Refactoring-Schritt: Tests laufen lassen

Die 13 ungueltigen Rationalisierungen

Diese Ausreden sind NIEMALS akzeptabel:

1. "Zu einfach zum Testen"

Realitaet: Einfacher Code braucht einfache Tests. 1 Zeile Test ist okay.

it('should add two numbers', () => {
  expect(add(2, 3)).toBe(5);
});

2. "Ich teste spaeter"

Realitaet: "Spaeter" bedeutet "nie". TDD bedeutet Test ZUERST.

3. "Bereits manuell getestet"

Realitaet: Manuelle Tests sind nicht reproduzierbar und skalieren nicht.

4. "Zeitdruck erlaubt keine Tests"

Realitaet: Tests sparen Zeit bei Debugging und verhindern Regressionen.

5. "Private Methoden muss man nicht testen"

Realitaet: Teste das Verhalten durch Public APIs. Wenn nicht testbar: Refactor.

6. "UI-Code kann man nicht testen"

Realitaet: React Testing Library, Playwright, Storybook existieren genau dafuer.

7. "Die Logik ist trivial"

Realitaet: Triviale Logik aendert sich. Tests dokumentieren erwartetes Verhalten.

8. "Wir haben einen QA-Prozess"

Realitaet: QA findet Bugs spaeter und teurer. TDD verhindert Bugs von Anfang an.

9. "Der Code ist nur temporaer"

Realitaet: Temporaerer Code lebt oft Jahre. Tests sichern auch temporaeren Code ab.

10. "Tests verlangsamen die Entwicklung"

Realitaet: TDD beschleunigt langfristig durch weniger Debugging und Regressionen.

11. "Legacy Code hat keine Tests"

Realitaet: Charakterisierungstests vor Aenderungen schreiben. Schrittweise verbessern.

12. "Das Framework/die Library testet das schon"

Realitaet: Teste DEINE Nutzung des Frameworks, nicht das Framework selbst.

13. "Mocking ist zu aufwaendig"

Realitaet: Wenn Mocking zu komplex ist, ist das Design zu komplex. Refactor.

Verification Checklist

Vor jedem Commit MUSS gelten:

  • Jede exportierte Funktion hat mindestens einen Test
  • Jeder Test ist VOR der Implementation fehlgeschlagen (RED beobachtet)
  • Jeder Test prueft genau EINE Sache (Single Assertion Principle)
  • Minimaler Code pro Test (kein Over-Engineering)
  • Edge Cases abgedeckt:
    • Null/Undefined Inputs
    • Leere Arrays/Strings
    • Grenzwerte (0, MAX_INT, negative Zahlen)
    • Fehlerhafte Inputs (TypeError erwartet)
  • Test-Namen beschreiben Verhalten: should [erwartetes Ergebnis] when [Bedingung]
  • Keine skip oder only Tests im Commit
  • Coverage mindestens 80% fuer neuen Code

TDD-Workflow in der Praxis

Schritt 1: Test-Datei erstellen

# Fuer neue Funktion in src/utils/oee.ts
touch src/utils/oee.test.ts

Schritt 2: Minimaler fehlschlagender Test

// src/utils/oee.test.ts
import { describe, it, expect } from 'vitest';
import { calculateOEE } from './oee';

describe('calculateOEE', () => {
  it('should return 85 for sample manufacturing data', () => {
    const result = calculateOEE({
      availability: 90,
      performance: 95,
      quality: 99
    });
    expect(result).toBeCloseTo(84.645, 2);
  });
});

Schritt 3: Test laufen lassen (MUSS fehlschlagen)

npm run test -- --run src/utils/oee.test.ts

# Erwartete Ausgabe:
# Error: Cannot find module './oee'
# ODER nach Stub:
# Error: Expected 84.645 but received undefined

Schritt 4: Minimale Implementation

// src/utils/oee.ts
export interface OEEParams {
  availability: number;
  performance: number;
  quality: number;
}

export function calculateOEE(params: OEEParams): number {
  return (params.availability * params.performance * params.quality) / 10000;
}

Schritt 5: Test laufen lassen (MUSS bestehen)

npm run test -- --run src/utils/oee.test.ts

# Erwartete Ausgabe:
# PASS src/utils/oee.test.ts

Schritt 6: Naechster Test fuer Edge Case

it('should throw when values exceed 100', () => {
  expect(() => calculateOEE({
    availability: 101,
    performance: 100,
    quality: 100
  })).toThrow('Values must be between 0 and 100');
});

Zurueck zu Schritt 3 (RED) -> Schritt 4 (GREEN) -> Repeat.

Anti-Patterns erkennen

VERBOTEN: Test nach Code

// FALSCH: Code zuerst geschrieben
function add(a: number, b: number): number {
  return a + b;
}

// Dann erst Test geschrieben - UNGUELTIG!
// Du weisst nicht ob der Test das richtige testet

VERBOTEN: Zu viel Code auf einmal

// FALSCH: Komplette Klasse ohne Tests implementiert
class UserService {
  async create(user: User) { ... }
  async update(id: string, data: Partial<User>) { ... }
  async delete(id: string) { ... }
  async findById(id: string) { ... }
  async findAll(filters: FilterOptions) { ... }
}

// RICHTIG: Eine Methode nach der anderen mit TDD

VERBOTEN: Tests anpassen damit sie bestehen

// FALSCH: Test geaendert weil Implementation anders ist
// Vorher: expect(result).toBe(100);
// Nachher: expect(result).toBe(99.5); // "Weil die Formel das so ausgibt"

// RICHTIG: Implementation korrigieren ODER Anforderungen klaeren

Framework-spezifische Patterns

React Components (Vitest + Testing Library)

import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';

describe('LoginButton', () => {
  it('should show loading spinner when clicked', async () => {
    render(<LoginButton onLogin={vi.fn()} />);

    await userEvent.click(screen.getByRole('button', { name: /login/i }));

    expect(screen.getByRole('progressbar')).toBeInTheDocument();
  });
});

API Endpoints (Supertest)

import request from 'supertest';
import { app } from '../app';

describe('POST /api/analyze', () => {
  it('should return 401 without authentication', async () => {
    const response = await request(app)
      .post('/api/analyze')
      .send({ data: 'test' });

    expect(response.status).toBe(401);
    expect(response.body.error).toBe('Unauthorized');
  });
});

Async Code

describe('fetchUserData', () => {
  it('should retry 3 times on network failure', async () => {
    const mockFetch = vi.fn()
      .mockRejectedValueOnce(new Error('Network'))
      .mockRejectedValueOnce(new Error('Network'))
      .mockResolvedValueOnce({ id: 1, name: 'Test' });

    const result = await fetchUserData(1, { fetch: mockFetch });

    expect(mockFetch).toHaveBeenCalledTimes(3);
    expect(result.name).toBe('Test');
  });
});

Bei Verstoß gegen TDD

  1. STOPP: Keine weitere Code-Generierung ohne Test
  2. WARNUNG: "TDD-Verstoß erkannt: [Beschreibung]"
  3. ANLEITUNG: Zeige den korrekten TDD-Workflow
  4. FRAGE: "Soll ich zuerst den Test schreiben?"

Metriken zur Erfolgsmessung

  • Test-to-Code Ratio: Mindestens 1:1 (Test-LOC zu Code-LOC)
  • Coverage: Minimum 80% fuer neuen Code
  • Red-Green Time: Kurze Zyklen (5-10 Minuten pro Feature)
  • Test Execution Time: Unit Tests unter 10 Sekunden

Kommandos

# Einzelnen Test laufen lassen (RED pruefen)
npm run test -- --run path/to/file.test.ts

# Alle Tests (vor Commit)
npm run test

# Coverage Report
npm run test:coverage

# Watch Mode (waehrend Entwicklung)
npm run test -- --watch

Integration mit anderen Skills

  • code-quality-gate: TDD Tests sind Teil von Gate 1 (Pre-Commit)
  • strict-typescript-mode: Tests muessen auch Type-safe sein
  • supervisor: Pruefer-Agent verifiziert TDD-Einhaltung

Quellen und Weiterfuehrende Literatur

  • Kent Beck: "Test-Driven Development: By Example"
  • Robert C. Martin: "Clean Code" (Kapitel 9: Unit Tests)
  • Martin Fowler: "Refactoring" (Test-Sicherheit bei Refactoring)

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Coding

social-media-content

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

reddit-research

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

linkedin-engagement

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

qa-checklist

No summary provided by upstream source.

Repository SourceNeeds Review