Sebastian Bergmann, Stefan Priebsch
Softwarequalität in PHP-Projekten
Mit Fallstudien von Firmen wie Facebook und Projekten wie TYPO3, Symfony und Zend Framework
Inhalt
6
Geleitwort
16
Vorwort
18
Teil I Grundlagen
28
1 Softwarequalität
30
1.1 Was ist Softwarequalität?
30
1.2 Externe Qualität
31
1.3 Interne Qualität
31
1.4 Technische Schulden
32
1.5 Konstruktive Qualitätssicherung
34
1.6 Sauberer Code
35
1.6.1 Explizite und minimale Abhängigkeiten
36
1.6.2 Klare Verantwortlichkeiten
36
1.6.3 Keine Duplikation
36
1.6.4 Kurze Methoden mit wenigen Ausführungszweigen
36
1.7 Software-Metriken
36
1.7.1 Zyklomatische Komplexität und NPath-Komplexität
37
1.7.2 Change Risk Anti-Patterns (CRAP) Index
37
1.7.3 Non-Mockable Total Recursive Cyclomatic Complexity
38
1.7.4 Global Mutable State
38
1.7.5 Kohäsion und Kopplung
39
1.8 Werkzeuge
39
1.9 Fazit
41
2 Testen von Software
44
2.1 Einführung
44
2.2 Systemtests
46
2.2.1 Testen im Browser
46
2.2.2 Automatisierte Tests
47
2.2.3 Testisolation
49
2.2.4 Akzeptanztests
50
2.2.5 Grenzen von Systemtests
50
2.3 Unit-Tests
51
2.3.1 Rückgabewerte
53
2.3.2 Abhängigkeiten
55
2.3.3 Seiteneffekte
56
2.3.4 Stub- und Mock-Objekte
56
2.4 Die Softwaretestpyramide
58
2.5 Integrationstests
63
2.5.1 Kollaborierende Systeme ersetzen
64
2.5.2 Datenbanken ersetzen
65
2.5.3 Die GUI (zunächst) ignorieren
65
2.5.4 Frontend-Tests
66
2.5.5 PHPUnit als Infrastruktur
66
2.5.6 Realisierung
67
2.6 Fazit
79
3 Testen von Legacy Code
80
3.1 Einführung
80
3.2 Praxisbeispiel
82
3.2.1 Vorbereitungen
85
3.2.2 Globale Abhängigkeiten
89
3.2.3 Datenquellen
90
3.2.4 Asynchrone Vorgänge
96
3.2.5 Änderungen in der Datenbank
101
3.2.6 Nicht vorhersagbare Ergebnisse
102
3.2.7 Eingabedaten
105
3.2.8 Weiterführende Überlegungen
106
3.3 Fazit
107
Teil II Fortgeschrittene Themen
108
4 Bad Practices in Unit-Tests
110
4.1 Einführung
110
4.2 Warum guter Testcode wichtig ist
110
4.3 Bad Practices und Test-Smells
111
4.3.1 Duplizierter Testcode
112
4.3.2 Zusicherungsroulette und begierige Tests
113
4.3.3 Fragile Tests
116
4.3.4 Obskure Tests
118
4.3.5 Lügende Tests
124
4.3.6 Langsame Tests
125
4.3.7 Konditionale Logik in Tests
127
4.3.8 Selbstvalidierende Tests
128
4.3.9 Websurfende Tests
129
4.3.10 Mock-Overkill
130
4.3.11 Skip-Epidemie
132
4.4 Fazit
132
5 Kontinuierliche Integration
134
5.1 Einführung
134
5.1.1 Kontinuierliche Integration
135
5.1.2 Statische Analyse
138
5.2 Installation und Inbetriebnahme
150
5.3 Konfiguration
150
5.3.1 Statische Tests
152
5.3.2 Dynamische Tests
158
5.3.3 Reporting
159
5.3.4 Deliverables erzeugen
160
5.4 Betrieb
162
5.5 Weiterführende Themen
162
5.5.1 Continuous Deployment
162
5.5.2 Einen Reverse Proxy nutzen
164
5.5.3 Kontinuierliche Integration und agile Paradigmen
164
5.6 Fazit
165
6 Testen von Datenbank-Interaktionen
168
6.1 Einführung
168
6.2 Pro und Kontra
169
6.2.1 Was gegen Datenbanktests spricht
169
6.2.2 Warum wir Datenbanktests schreiben sollten
170
6.3 Was wir testen sollten
171
6.4 Datenbanktests schreiben
172
6.4.1 Die Datenbankverbindung mocken
172
6.4.2 Die Datenbankerweiterung von PHPUnit
173
6.4.3 Die Klasse für Datenbanktestfälle
174
6.4.4 Die Verbindung zur Testdatenbank aufbauen
175
6.4.5 Datenbestände erzeugen
178
6.4.6 Operationen auf den Daten
193
6.4.7 Tests schreiben
196
6.4.8 Den Datenbanktester benutzen
203
6.5 Testgetriebene Entwicklung und Datenbanktests
206
6.6 Datenbanktests als Regressionstests
206
6.6.1 Probleme mit den Daten testen
207
6.6.2 Probleme testen, die durch Daten sichtbar werden
208
6.7 Fazit
209
7 Gebrauchstauglichkeit
210
7.1 Einführung
210
7.2 Anything goes – aber zu welchem Preis?
212
7.3 Designaspekte
213
7.3.1 Barrierefreiheit
213
7.3.2 Lesbarkeit
214
7.3.3 Label für Formularelemente
215
7.3.4 Tastaturbedienbare Webseite
215
7.3.5 Gute Farbkontraste
216
7.3.6 Logo zur Startseite verlinken
217
7.3.7 Alternativtexte für Bilder
217
7.3.8 Hintergrundbild mit Hintergrundfarbe
217
7.3.9 Druckversion nicht vergessen
217
7.3.10 Erkennbare Links
217
7.3.11 Gute Bookmarks
218
7.3.12 Keine Frames
218
7.3.13 Skalierbare Schrift
218
7.4 Technische Aspekte
219
7.4.1 Performanz
219
7.4.2 JavaScript
221
7.5 Benutzerführung
222
7.5.1 Der Mythos des Falzes
222
7.5.2 Feedback bei Interaktionen
223
7.5.3 Navigation
223
7.5.4 Popups und andere Störenfriede
224
7.5.5 Gewohnheiten bedienen, Erwartungen nicht enttäuschen
225
7.5.6 Fehlertoleranz und Feedback
226
7.6 Testen der Usability
226
7.7 Fazit
227
8 Performanz
230
8.1 Einführung
230
8.1.1 Werkzeuge
231
8.1.2 Umgebungsbezogene Gesichtspunkte
232
8.2 Lasttests
233
8.2.1 Apache Bench
234
8.2.2 Pylot
236
8.2.3 Weitere Werkzeuge für Lasttests
238
8.3 Profiling
239
8.3.1 Callgrind
240
8.3.2 APD
244
8.3.3 Xdebug
246
8.3.4 XHProf
246
8.3.5 OProfile
249
8.4 Systemmetriken
250
8.4.1 strace
250
8.4.2 Sysstat
251
8.4.3 Lösungen im Eigenbau
253
8.5 Übliche Fallstricke
254
8.5.1 Entwicklungsumgebung gegen Produktivumgebung
254
8.5.2 CPU-Zeit
254
8.5.3 Mikro-Optimierungen
255
8.5.4 PHP als Glue Language
255
8.5.5 Priorisierung von Optimierungen
256
8.6 Fazit
257
9 Sicherheit
258
9.1 Was ist eigentlich Sicherheit?
258
9.2 Secure by Design
259
9.2.1 Der Betrieb
259
9.2.2 Physikalischer Zugang
260
9.2.3 Software-Entwicklung
261
9.3 Was kostet Sicherheit?
264
9.4 Die häufigsten Probleme
265
9.5 Fazit
274
10 Testbasierte Entwicklung verkaufen
276
10.1 Vom prozeduralen Code zum testbasierten Vorgehen
276
10.2 Ziele der testbasierten Entwicklung
278
10.3 Aufwände für Software-Entwicklung
279
10.4 Möglichst wenige technische Schulden aufnehmen!
281
10.5 Offenlegung von Risiken mit ATAM
282
10.5.1 Diskutieren und entscheiden
285
10.5.2 Mit ATAM transparente Entscheidungen herbeiführen
285
10.6 Kalkulation testbasierter Entwicklung
285
10.6.1 Risiken als Argumentationshilfe berechnen
286
10.6.2 Langsamere Entwicklung bei höherer Qualität
286
10.6.3 Automatisierungs- und Abdeckungsgrad durch Tests bestimmen
288
10.7 Strategische Argumente für die Einführung testbasierter Entwicklung
289
10.7.1 Qualität und Nachhaltigkeit als Teil des Leistungsversprechens
289
10.7.2 Initiale Mehraufwände, die sich für den Auftraggeber lohnen
290
10.8 Das Angebot richtig verhandeln
291
10.9 Formulierung des Angebots
295
10.9.1 Inhalte des Angebots
296
10.9.2 Ein Angebot ohne Verhandlung abgeben?
296
10.10 Fazit
297
Teil III Fallstudien: Open-Source
298
11 TYPO3: die agile Zukunft eines schwergewichtigen Projekts
300
11.1 Einführung
300
11.1.1 Die Geschichte von TYPO3 – 13 Jahre in 13 Absätzen
300
11.1.2 Den Neuanfang wagen!
302
11.1.3 Unsere Erfahrungen mit dem Testen
303
11.2 Grundsätze und Techniken
304
11.2.1 Bittersüße Elefantenstückchen
304
11.2.2 Testgetriebene Entwicklung
305
11.2.3 Tests als Dokumentation
306
11.2.4 Kontinuierliche Integration
307
11.2.5 Sauberer Code
308
11.2.6 Refaktorierung
309
11.2.7 Programmierrichtlinien
310
11.2.8 Domänengetriebenes Design
312
11.3 Vorgehen bei der Entwicklung
312
11.3.1 Neuen Code entwickeln
313
11.3.2 Code erweitern und ändern
313
11.3.3 Code optimieren
314
11.3.4 Fehler finden und beheben
316
11.3.5 Alten Code fachgerecht entsorgen
316
11.4 Testrezepte
317
11.4.1 Ungewollt funktionale Unit-Tests
317
11.4.2 Zugriffe auf das Dateisystem
318
11.4.3 Konstruktoren in Interfaces
319
11.4.4 Abstrakte Klassen testen
320
11.4.5 Testen von geschützten Methoden
320
11.4.6 Verwendung von Callbacks
322
11.5 Auf in die Zukunft
324
12 Testen von Symfony und Symfony-Projekten
326
12.1 Einführung
326
12.2 Ein Framework testen
327
12.2.1 Der Release-Management-Prozess von Symfony
327
12.2.2 Verhältnis von Testcode und getestetem Code
329
12.2.3 Die Ausführung der Testsuite muss schnell sein
329
12.2.4 Gesammelte Erfahrungen
330
12.3 Testen von Webanwendungen
335
12.3.1 Die Hemmschwelle für das Testen abbauen
335
12.3.2 Unit-Tests
336
12.3.3 Funktionale Tests
341
12.4 Fazit
345
13 Testen von Grafikausgaben
346
13.1 Einführung
346
13.2 Entwicklungsphilosophie
347
13.3 Die ezcGraph-Komponente
347
13.3.1 Architektur
349
13.4 Ausgabetreiber durch Mock-Objekt ersetzen
1
13.4.1 Mehrfache Erwartungen
352
13.4.2 Structs
353
13.4.3 Generierung der Erwartungen
354
13.4.4 Zusammenfassung
355
13.5 Binäre Ausgaben testen
355
13.5.1 Die Ausgabetreiber
356
13.5.2 Generierung der Erwartungen
356
13.5.3 SVG
357
13.5.4 Bitmap-Erzeugung
358
13.5.5 Flash
361
13.6 Fazit
364
14 Testen von serviceorientierten APIs
366
14.1 Die Probleme
368
14.2 API-Zugangskennungen
369
14.3 API-Beschränkungen
372
14.4 Service-Protokolle offline testen
373
14.5 Konkrete Services offline testen
378
14.6 Fazit
383
15 Wie man einen WebDAV-Server testet
384
15.1 Über die eZ WebDAV-Komponente
384
15.1.1 WebDAV
384
15.1.2 Architektur
386
15.2 Herausforderungen bei der Entwicklung
388
15.2.1 Anforderungsanalyse
388
15.2.2 TDD nach RFC
389
15.2.3 Den Server testen
390
15.3 Automatisierte Akzeptanztests mit PHPUnit
392
15.3.1 Test-Trails aufzeichnen
394
15.3.2 Das Testrezept
395
15.3.3 Integration mit PHPUnit
396
15.4 Fazit
405
Teil IV Fallstudien: Unternehmen
406
16 swoodoo – eine wahrhaft agile Geschichte
408
16.1 Einführung
408
16.2 Evolution: Nur die Starken überleben
408
16.3 Wie wir die „eXtreme Seite“ erreichten
413
16.3.1 Kontinuierliche Integration
414
16.3.2 Testgetriebene Entwicklung
415
16.3.3 Tägliche Standup-Meetings
415
16.4 Wo wir schon einmal dabei sind ...
417
16.4.1 User Storys und Story Points
417
16.4.2 Velocity
418
16.4.3 Iterationsplanung
419
16.4.4 Programmieren in Paaren
419
16.4.5 Kollektives Eigentum
420
16.4.6 Offenheit für Änderungen
422
16.4.7 Überstunden
423
16.5 Die Kunst der Evolution
423
16.6 KISS und YAGNI – zwei Seiten einer Medaille
429
16.7 Evolutionstheorie und Fazit
429
17 Qualitätssicherung bei studiVZ
432
17.1 Einführung
432
17.2 Akzeptanztests
434
17.3 Selenium
435
17.3.1 Die Selenium-Erweiterung von PHPUnit
437
17.4 Technisches Setup von studiVZ
438
17.4.1 Codeumgebung
438
17.4.2 Testumgebung
439
17.5 Best Practices
440
17.5.1 Jugendsünden
440
17.5.2 Strategiewechsel
442
17.6 Eine DSL muss her
452
17.6.1 Interne DSL
453
17.6.2 Testing_SeleniumDSL 1.0
454
17.6.3 Testing_SeleniumDSL 2.0 – ein Entwurf
456
17.7 Fazit
458
18 Qualitätssicherung bei Digg
460
18.1 Die Ausgangssituation
460
18.1.1 Unsere Probleme
460
18.1.2 Code-Altlasten
461
18.1.3 Wie lösen wir unsere Probleme?
462
18.1.4 Ein Test-Framework wählen
464
18.1.5 Mit einem Experten arbeiten
465
18.2 Das Team trainieren
465
18.3 Testbaren Code schreiben
469
18.3.1 Statische Methoden vermeiden
469
18.3.2 Dependency Injection
472
18.4 Mock-Objekte
472
18.4.1 Überblick
472
18.4.2 Datenbank
472
18.4.3 Lose gekoppelte Abhängigkeiten
473
18.4.4 Beobachter für klasseninternes Verhalten
474
18.4.5 Memcache
476
18.4.6 Mocken einer serviceorientierten Architektur
477
18.5 Der Qualitätssicherungsprozess bei Digg
481
18.5.1 Testen
481
18.5.2 Vorteile
483
18.5.3 Herausforderungen
484
18.6 Fazit
485
Schlussbetrachtungen
486
Literatur
488
Stichwortverzeichnis
494
© 2009-2024 ciando GmbH