Der Test-Driven-Development-Workflow
Das Design mit dem Red-Green-Refactor-Zyklus vorantreiben
Der Test-Driven-Development-Workflow ist eine kostenlose PHP Academy-Lektion auf CoddyKit. Dies ist Lektion 1 von 4. Du kannst die komplette Lektion unten kostenlos lesen – dann übst du sie direkt im Browser mit einem integrierten Code-Editor und einem KI-Tutor rund um die Uhr. Sie ist Teil des PHP Academy-Lernpfads, und dein Fortschritt wird über Web und CoddyKit-App synchronisiert. Der PHP Academy-Kurs umfasst insgesamt 4 Lektionen.
TDD ist ein Werkzeug für das Design
Test-Driven Development wird oft als Testtechnik vermarktet, aber sein eigentlicher Wert liegt im Designdruck. Indem Sie den Test zuerst schreiben, müssen Sie die öffentliche Schnittstelle eines Objekts, seine Abhängigkeiten und seinen Vertrag definieren, bevor Sie eine Implementierung schreiben. Die Tests sind ein Nebenprodukt; besseres Design ist das eigentliche Ergebnis.
Rot, Grün, Refactoring
Der Zyklus besteht aus drei strikt getrennten Phasen:
- Rot – schreiben Sie einen fehlschlagenden Test für das nächste kleine Verhalten. Er muss aus dem richtigen Grund fehlschlagen.
- Grün – schreiben Sie den minimalen Code, der den Test bestehen lässt, auch wenn er unschön ist.
- Refactoring – bereinigen Sie Implementierung und Tests, solange alle Tests weiterhin grün sind.
Disziplin ist wichtig: Überspringen Sie niemals Rot (sonst testen Sie möglicherweise nichts), und bauen Sie in Grün nie mehr als nötig.
Rot: Den fehlschlagenden Test zuerst schreiben
Wir erstellen einen PriceCalculator, der einen prozentualen Rabatt anwendet. Beginnen Sie mit einem Test für ein Verhalten, das noch nicht existiert. Beim Ausführen sollte er fehlschlagen, weil die Klasse nicht definiert ist – das ist ein gültiges Rot.
<?php
use PHPUnit\Framework\TestCase;
final class PriceCalculatorTest extends TestCase
{
public function test_applies_a_percentage_discount(): void
{
$calc = new PriceCalculator();
// 100 with 10% off -> 90.0
self::assertSame(90.0, $calc->withDiscount(100.0, 10));
}
}
Grün: Minimalen Code zum Bestehen schreiben
Schreiben Sie nun die kleinstmögliche Implementierung, die den Test grün werden lässt. Widerstehen Sie der Versuchung, Rundungsregeln, Validierung oder Währungsbehandlung hinzuzufügen – bisher gibt es keinen fehlschlagenden Test, der dies verlangt.
<?php
final class PriceCalculator
{
public function withDiscount(float $amount, float $percent): float
{
return $amount - ($amount * $percent / 100);
}
}
$calc = new PriceCalculator();
var_dump($calc->withDiscount(100.0, 10)); // float(90)
Durch Triangulation zur Verallgemeinerung
Ein einzelner Test kann durch eine fest codierte Lösung erfüllt werden. Triangulation – das Hinzufügen eines zweiten, unterschiedlichen Beispiels – zwingt die Implementierung zur Verallgemeinerung. Fügen Sie einen Fall hinzu, den die triviale Lösung nicht vortäuschen kann, und leiten Sie so die tatsächliche Formel her.
<?php
use PHPUnit\Framework\TestCase;
final class PriceCalculatorTest extends TestCase
{
public function test_zero_percent_is_unchanged(): void
{
self::assertSame(50.0, (new PriceCalculator())->withDiscount(50.0, 0));
}
public function test_full_discount_is_free(): void
{
self::assertSame(0.0, (new PriceCalculator())->withDiscount(50.0, 100));
}
}
Grenzfälle als Spezifikationen vorgeben
In TDD wird eine neue Anforderung zu einem neuen fehlschlagenden Test. Angenommen, negative Rabatte sind ungültig. Schreiben Sie zuerst den Test, der eine Exception erwartet. Er schlägt fehl, weil bisher nichts ausgelöst wird. Der Test dokumentiert den Vertrag.
<?php
use PHPUnit\Framework\TestCase;
final class PriceCalculatorValidationTest extends TestCase
{
public function test_rejects_negative_discount(): void
{
$this->expectException(\InvalidArgumentException::class);
(new PriceCalculator())->withDiscount(100.0, -5);
}
}
Wieder grün werden, dann Refactoring
Fügen Sie die Schutzprüfung hinzu, damit der neue Test besteht, und führen Sie anschließend vertrauensvoll ein Refactoring durch – die vorhandenen Tests erkennen Regressionen. Beachten Sie, dass wir auch die Rundung erst eingeführt haben, nachdem ein Test (oder eine bekannte Anforderung) sie gerechtfertigt hat.
<?php
final class PriceCalculator
{
public function withDiscount(float $amount, float $percent): float
{
if ($percent < 0 || $percent > 100) {
throw new \InvalidArgumentException('percent must be 0..100');
}
return round($amount - ($amount * $percent / 100), 2);
}
}
var_dump((new PriceCalculator())->withDiscount(19.99, 15)); // float(16.99)
Data Provider fassen Beispiele zusammen
Sobald ein Verhalten stabil ist, fassen Sie viele Beispielpaare in einem einzigen parametrisierten Test mit einem Data Provider zusammen. So bleibt die Rot-Grün-Schleife schnell und die Tabelle der Testabsicht übersichtlich.
<?php
use PHPUnit\Framework\TestCase;
use PHPUnit\Framework\Attributes\DataProvider;
final class DiscountTableTest extends TestCase
{
#[DataProvider('cases')]
public function test_discounts(float $amount, float $pct, float $expected): void
{
self::assertSame($expected, (new PriceCalculator())->withDiscount($amount, $pct));
}
public static function cases(): array
{
return [
'no discount' => [100.0, 0, 100.0],
'ten percent' => [100.0, 10, 90.0],
'free' => [100.0, 100, 0.0],
];
}
}
Die Schleife schnell halten
TDD funktioniert nur, wenn die Feedbackschleife Sekunden statt Minuten dauert. Praktische Stellschrauben:
- Führen Sie eine einzelne Datei aus oder filtern Sie Tests:
phpunit --filter test_full_discount_is_free. - Verwenden Sie
--testdox, um Tests als Verhaltensspezifikation zu lesen. - Halten Sie Unit-Tests frei von I/O – keine Datenbank, kein Netzwerk und kein Dateisystem in der inneren Schleife.
vendor/bin/phpunit --testdox --filter PriceCalculatorAuch Tests refaktorisieren
Die Refactoring-Phase umfasst die Testsuite, nicht nur den Produktionscode. Entfernen Sie Duplikate mit Hilfsmethoden und setUp(), benennen Sie Tests nach ihrem Verhalten und löschen Sie Tests, die nichts Sinnvolles mehr prüfen. Tests sind Code, den Sie dauerhaft pflegen – behandeln Sie ihn genauso sorgfältig.
<?php
use PHPUnit\Framework\TestCase;
final class PriceCalculatorTest extends TestCase
{
private PriceCalculator $calc;
protected function setUp(): void
{
$this->calc = new PriceCalculator(); // shared setup, no duplication
}
public function test_ten_percent(): void
{
self::assertSame(90.0, $this->calc->withDiscount(100.0, 10));
}
}
TDD formt Abhängigkeiten
Da Sie den Test zuerst schreiben, werden umständliche Abhängigkeiten sofort sichtbar. Wenn sich eine Klasse nur schwer in einem Test instanziieren lässt, ist das ein Designhinweis: Injizieren Sie abhängige Komponenten, statt sie innerhalb der Klasse mit new zu erzeugen. Der folgende Rabattrechner wird testbar, indem er seine Rundungsstrategie entgegennimmt, statt sie fest zu codieren – TDD hat diese Erweiterungsstelle erzwungen.
<?php
interface RoundingPolicy { public function round(float $v): float; }
final class PriceCalculator
{
public function __construct(private RoundingPolicy $rounding) {}
public function withDiscount(float $amount, float $percent): float
{
return $this->rounding->round($amount - ($amount * $percent / 100));
}
}
// Tests inject a deterministic RoundingPolicy; no hidden global behavior.
Schnelltest
Was ist der Zweck des roten Schritts?
Zusammenfassung
Sie haben TDD als Designdisziplin angewendet:
- Rot-Grün-Refactoring: fehlschlagender Test, minimaler Code und anschließendes Aufräumen bei weiterhin grünen Tests.
- Triangulation erzwingt Verallgemeinerung; neue Anforderungen werden zu neuen fehlschlagenden Tests.
- Data Provider fassen stabile Fälle zusammen;
--filter/--testdoxhalten die Schleife schnell. - Refaktorisieren Sie auch Ihre Tests – sie sind langlebiger Code.
Als Nächstes: flexible Test-Doubles mit Mockery.
Häufig gestellte Fragen
Ist die Lektion „Der Test-Driven-Development-Workflow“ kostenlos?
Ja — der vollständige Text von „Der Test-Driven-Development-Workflow“ ist hier im Web kostenlos zu lesen. Um sie interaktiv zu üben (integrierter Code-Editor und 24/7 KI-Tutor) und den Rest des PHP Academy-Kurses freizuschalten, upgrade auf CoddyKit PRO. Der PHP Academy-Kurs umfasst insgesamt 4 Lektionen.
Was lerne ich in „Der Test-Driven-Development-Workflow“?
Das Design mit dem Red-Green-Refactor-Zyklus vorantreiben Du übst PHP Academy mit praktischem Code, den du direkt im Browser ausführst, und ein 24/7 KI-Tutor beantwortet deine Fragen während du die Lektion bearbeitest.
Brauche ich Erfahrung, um PHP Academy zu starten?
Keine Vorkenntnisse erforderlich. PHP Academy auf CoddyKit ist für Anfänger bis fortgeschrittene Lernende strukturiert, sodass du hier starten oder von Anfang an beginnen und in deinem eigenen Tempo voranschreiten kannst. Dies ist Lektion 1 von 4.
Wie lange dauert die Lektion „Der Test-Driven-Development-Workflow“?
Die meisten CoddyKit-Lektionen dauern etwa 5–10 Minuten. Jede ist kompakt und interaktiv, sodass du stetig Fortschritte machst und genau dort weitermachst, wo du aufgehört hast – im Web und in der App.
Kann ich in dieser PHP Academy-Lektion Code schreiben und ausführen?
Ja. Jede PHP Academy-Lektion enthält einen integrierten Code-Editor, sodass du echten Code direkt in deinem Browser schreibst und ausführst und sofort KI-Feedback erhältst — ohne lokale Einrichtung erforderlich.
Alle Lektionen in diesem Kurs
- Der Test-Driven-Development-Workflow
- Mocking und Stubbing mit Mockery
- Integrations- und Funktionstests
- Mutation Testing mit Infection