Osherove / Feathers / Martin The Art of Unit Testing
2.; überarbeitete Auflage 2015
ISBN: 978-3-8266-8721-1
Verlag: mitp Verlags GmbH & Co.KG
Format: PDF
Kopierschutz: 0 - No protection
Deutsche Ausgabe
E-Book, Deutsch, 288 Seiten
Reihe: mitp Professional
ISBN: 978-3-8266-8721-1
Verlag: mitp Verlags GmbH & Co.KG
Format: PDF
Kopierschutz: 0 - No protection
Lesbare, wartbare und zuverlässige Tests entwickeln
Fakes, Stubs, Mock-Objekte und Isolation-(Mocking-)Frameworks
Einfache Dependency-Injection-Techniken und das Refactoring von Legacy Code
Sie wissen, dass Sie Unit Tests durchführen sollten – warum machen Sie es noch nicht? Wenn Sie Anfänger auf dem Gebiet der Unit Tests sind, wenn Sie Unit Tests mühsam finden oder wenn Sie, gemessen am Aufwand, einfach kein ausreichendes Ergebnis erzielen, dann sollten Sie dieses Buch lesen.
Roy Osherove führt Sie Schritt für Schritt vom Schreiben Ihres ersten, einfachen Unit Tests bis hin zum Erstellen kompletter Test-Sets, die wartbar, lesbar und zuverlässig sind. Sie werden schnell zu fortgeschrittenen Themen wie Mocks und Stubs hingeführt, während Sie die Verwendung von Isolation-(Mocking-)Frameworks wie Moq, FakeItEasy und Typemock Isolator erlernen. Sie erfahren eine Menge zu Testmustern und zur Testorganisation, führen Refactoring durch und lernen, wie man »untestbaren« Code testet. Nebenbei zeigt Ihnen der Autor das Integration Testing sowie Techniken zum Testen mit Datenbanken.
Die Beispiele im Buch verwenden C#, sind aber auch für jeden nützlich, der eine Sprache mit statischen Typen wie Java oder C++ benutzt.
Aus dem Inhalt:
Grundlagen des Unit Testings
Frameworks für das Unit Testing
Einsatz von NUnit
Stubs zum Auflösen von Abhängigkeiten
Interaction Testing mit Mock-Objekten
Isolation-(Mocking-)Frameworks
Testhierarchie und Organisation
Die Säulen guter Unit Tests
Integration von Unit Tests in das Unternehmen
Umgang mit Legacy Code
Design und Testbarkeit
Tools und Frameworks
Stimmen zum Buch:
»Dieses Buch ist etwas Besonderes. Die Kapitel bauen aufeinander auf und entwickeln eine erstaunliche Tiefe.«
– Aus dem Vorwort von Robert C. Martin, cleancoder.com
»Die beste Art, Unit Testing zu lernen. Bereits ein Klassiker auf dem Gebiet.«
– Raphael Faria, LG Electronics
»Bringt Ihnen sowohl die Philosophie des effektiven Unit Testings bei als auch die praktischen Grundlagen.«
– Pradeep Chellappan, Microsoft
»Wenn meine Teammitglieder fragen, wie sie Unit Tests richtig schreiben sollen, antworte ich einfach: mit diesem Buch!«
– Alessandro Campeis, Vimar SpA
Zielgruppe
Software-Entwickler für .NET sowie andere Programmiersprachen.
Autoren/Hrsg.
Weitere Infos & Material
1;Cover;1
2;Titel;3
3;Impressum;4
4;Inhaltsverzeichnis;5
5;Vorwort zur zweiten Auflage;13
6;Vorwort zur ersten Auflage;15
7;Einleitung;17
8;Kapitel 1: Die Grundlagen des Unit Testings;25
8.1;1.1 Unit Testing – Schritt für Schritt definiert;25
8.1.1;1.1.1 Die Bedeutung guter Unit Tests;27
8.1.2;1.1.2 Wir alle haben schon Unit Tests geschrieben (irgendwie);27
8.2;1.2 Eigenschaften eines »guten« Unit Tests;28
8.3;1.3 Integrationstests;29
8.3.1;1.3.1 Nachteile von nicht automatisierten Integrationstests im Vergleich zu automatisierten Unit Tests;31
8.4;1.4 Was Unit Tests »gut« macht;33
8.5;1.5 Ein einfaches Unit-Test-Beispiel;34
8.6;1.6 Testgetriebene Entwicklung;38
8.7;1.7 Die drei Schlüsselqualifikationen für erfolgreiches TDD;41
8.8;1.8 Zusammenfassung;41
9;Kapitel 2: Ein erster Unit Test;43
9.1;2.1 Frameworks für das Unit Testing;44
9.1.1;2.1.1 Was Unit-Testing-Frameworks bieten;44
9.1.2;2.1.2 Die xUnit-Frameworks;46
9.2;2.2 Das LogAn-Projekt wird vorgestellt;47
9.3;2.3 Die ersten Schritte mit NUnit;47
9.3.1;2.3.1 Die Installation von NUnit;47
9.3.2;2.3.2 Das Laden der Projektmappe;49
9.3.3;2.3.3 Die Verwendung der NUnit-Attribute in Ihrem Code;52
9.4;2.4 Sie schreiben Ihren ersten Test;53
9.4.1;2.4.1 Die Klasse Assert;53
9.4.2;2.4.2 Sie führen Ihren ersten Test mit NUnit aus;54
9.4.3;2.4.3 Sie fügen positive Tests hinzu;55
9.4.4;2.4.4 Von Rot nach Grün: das erfolgreiche Ausführen der Tests;56
9.4.5;2.4.5 Test-Code-Gestaltung;57
9.5;2.5 Refactoring zu parametrisierten Tests;57
9.6;2.6 Weitere NUnit-Attribute;60
9.6.1;2.6.1 Aufbau und Abbau;60
9.6.2;2.6.2 Auf erwartete Ausnahmen prüfen;64
9.6.3;2.6.3 Das Ignorieren von Tests;66
9.6.4;2.6.4 Die fließende Syntax von NUnit;67
9.6.5;2.6.5 Das Festlegen der Testkategorien;67
9.7;2.7 Das Testen auf Zustandsänderungen des Systems statt auf Rückgabewerte;68
9.8;2.8 Zusammenfassung;73
10;Kapitel 3: Die Verwendung von Stubs, um Abhängigkeiten aufzulösen;77
10.1;3.1 Die Stubs werden vorgestellt;77
10.2;3.2 Die Identifizierung einer Dateisystemabhängigkeit in LogAn;78
10.3;3.3 Die Entscheidung, wie LogAnalyzer am einfachsten getestet werden kann;79
10.4;3.4 Design-Refactoring zur Verbesserung der Testbarkeit;82
10.4.1;3.4.1 Extrahiere ein Interface, um die dahinter liegende Implementierung durch eine andere ersetzen zu können;83
10.4.2;3.4.2 Dependency Injection: Injiziere eine Fake-Implementierung in die zu testende Unit;86
10.4.3;3.4.3 Injiziere einen Fake auf Konstruktor-Ebene (Construktor Injection);86
10.4.4;3.4.4 Simuliere Ausnahmen über Fakes;91
10.4.5;3.4.5 Injiziere ein Fake als Property Get oder Set;92
10.4.6;3.4.6 Injiziere einen Fake unmittelbar vor einem Methodenaufruf;93
10.5;3.5 Variationen der Refactoring-Technik;101
10.5.1;3.5.1 Die Verwendung von Extract and Override, um Fake-Resultate zu erzeugen;101
10.6;3.6 Die Überwindung des Kapselungsproblems;103
10.6.1;3.6.1 Die Verwendung von internal und [InternalsVisibleTo];104
10.6.2;3.6.2 Die Verwendung des Attributs [Conditional];104
10.6.3;3.6.3 Die Verwendung von #if und #endif zur bedingten Kompilierung;105
10.7;3.7 Zusammenfassung;106
11;Kapitel 4: Interaction Testing mit Mock-Objekten;107
11.1;4.1 Wertbasiertes Testen versus zustandsbasiertes Testen versus Testen versus Interaction Testing;107
11.2;4.2 Der Unterschied zwischen Mocks und Stubs;110
11.3;4.3 Ein einfaches manuelles Mock-Beispiel;111
11.4;4.4 Die gemeinsame Verwendung von Mock und Stub;114
11.5;4.5 Ein Mock pro Test;119
11.6;4.6 Fake-Ketten: Stubs, die Mocks oder andere Stubs erzeugen;119
11.7;4.7 Die Probleme mit handgeschriebenen Mocks und Stubs;121
11.8;4.8 Zusammenfassung;122
12;Kapitel 5: Isolation-(Mock-Objekt-)Frameworks;123
12.1;5.1 Warum überhaupt Isolation-Frameworks?;123
12.2;5.2 Das dynamische Erzeugen eines Fake-Objekts;125
12.2.1;5.2.1 Die Einführung von NSubstitute in Ihre Tests;126
12.2.2;5.2.2 Das Ersetzen eines handgeschriebenen Fake-Objekts durch ein dynamisches;127
12.3;5.3 Die Simulation von Fake-Werten;130
12.3.1;5.3.1 Ein Mock, ein Stub und ein Ausflug in einen Test;131
12.4;5.4 Das Testen auf ereignisbezogene Aktivitäten;137
12.4.1;5.4.1 Das Testen eines Event Listeners;137
12.4.2;5.4.2 Der Test, ob ein Event getriggert wurde;139
12.5;5.5 Die aktuellen Isolation-Frameworks für .NET;139
12.6;5.6 Die Vorteile und Fallstricke von Isolation-Frameworks;141
12.6.1;5.6.1 Fallstricke, die man bei der Verwendung von Isolation-Frameworks besser vermeidet;141
12.6.2;5.6.2 Unlesbarer Testcode;142
12.6.3;5.6.3 Die Verifizierung der falschen Dinge;142
12.6.4;5.6.4 Die Verwendung von mehr als einem Mock pro Test;142
12.6.5;5.6.5 Die Überspezifizierung von Tests;142
12.7;5.7 Zusammenfassung;143
13;Kapitel 6: Wir tauchen tiefer ein in die Isolation-Frameworks;145
13.1;6.1 Eingeschränkte und uneingeschränkte Frameworks;145
13.1.1;6.1.1 Eingeschränkte Frameworks;145
13.1.2;6.1.2 Uneingeschränkte Frameworks;146
13.1.3;6.1.3 Wie Profiler-basierte uneingeschränkte Frameworks arbeiten;148
13.2;6.2 Werte guter Isolation-Frameworks;150
13.3;6.3 Eigenschaften, die Zukunftssicherheit und Benutzerfreundlichkeit unterstützen;150
13.3.1;6.3.1 Rekursive Fakes;151
13.3.2;6.3.2 Ignoriere Argumente als Voreinstellung;152
13.3.3;6.3.3 Umfangreiches Fälschen;152
13.3.4;6.3.4 Nicht striktes Verhalten von Fakes;152
13.3.5;6.3.5 Nicht strikte Mocks;153
13.4;6.4 Isolation-Framework-Design-Antimuster;154
13.4.1;6.4.1 Konzept-Konfusion;154
13.4.2;6.4.2 Aufnahme und Wiedergabe;155
13.4.3;6.4.3 Klebriges Verhalten;157
13.4.4;6.4.4 Komplexe Syntax;157
13.5;6.5 Zusammenfassung;158
14;Kapitel 7: Testhierarchie und Organisation;161
14.1;7.1 Automatisierte Builds, die automatisierte Tests laufen lassen;161
14.1.1;7.1.1 Die Anatomie eines Build-Skripts;163
14.1.2;7.1.2 Das Anstoßen von Builds und Integration;164
14.2;7.2 Testentwürfe, die auf Geschwindigkeit und Typ basieren;165
14.2.1;7.2.1 Der menschliche Faktor beim Trennen von Unit und Integrationstests;166
14.2.2;7.2.2 Die sichere grüne Zone;167
14.3;7.3 Stellen Sie sicher, dass die Tests zu Ihrer Quellcodekontrolle gehören;168
14.4;7.4 Das Abbilden der Testklassen auf den zu testenden Code;168
14.4.1;7.4.1 Das Abbilden von Tests auf Projekte;168
14.4.2;7.4.2 Das Abbilden von Tests auf Klassen;169
14.4.3;7.4.3 Das Abbilden von Tests auf bestimmte Methoden;170
14.5;7.5 Querschnittsbelang-Injektion;170
14.6;7.6 Der Bau einer Test-API für Ihre Applikation;173
14.6.1;7.6.1 Die Verwendung von Testklassen-Vererbungsmustern;173
14.6.2;7.6.2 Der Entwurf von Test-Hilfsklassen und -Hilfsmethoden;188
14.6.3;7.6.3 Machen Sie Ihre API den Entwicklern bekannt;189
14.7;7.7 Zusammenfassung;190
15;Kapitel 8: Die Säulen guter Unit Tests;191
15.1;8.1 Das Schreiben vertrauenswürdiger Tests;191
15.1.1;8.1.1 Die Entscheidung, wann Tests entfernt oder geändert werden;192
15.1.2;8.1.2 Vermeiden Sie Logik in Tests;197
15.1.3;8.1.3 Testen Sie nur einen Belang;199
15.1.4;8.1.4 Trennen Sie Unit Tests von Integrationstests;200
15.1.5;8.1.5 Stellen Sie Code-Reviews mit Codeabdeckung sicher;200
15.2;8.2 Das Schreiben wartbarer Tests;202
15.2.1;8.2.1 Das Testen privater oder geschützter Methoden;202
15.2.2;8.2.2 Das Entfernen von Duplizitäten;204
15.2.3;8.2.3 Die Verwendung von Setup-Methoden in einer wartbaren Art und Weise;208
15.2.4;8.2.4 Das Erzwingen der Test-Isolierung;211
15.2.5;8.2.5 Vermeiden Sie mehrfache Asserts für unterschiedliche Belange;217
15.2.6;8.2.6 Der Vergleich von Objekten;219
15.2.7;8.2.7 Vermeiden Sie eine Überspezifizierung der Tests;222
15.3;8.3 Das Schreiben lesbarer Tests;224
15.3.1;8.3.1 Die Benennung der Unit Tests;225
15.3.2;8.3.2 Die Benennung der Variablen;226
15.3.3;8.3.3 Benachrichtigen Sie sinnvoll;227
15.3.4;8.3.4 Das Trennen der Asserts von den Aktionen;228
15.3.5;8.3.5 Aufbauen und Abreißen;229
15.4;8.4 Zusammenfassung;229
16;Kapitel 9: Die Integration von Unit Tests in die Organisation;233
16.1;9.1 Schritte, um ein Agent des Wandels zu werden;233
16.1.1;9.1.1 Seien Sie auf die schweren Fragen vorbereitet;234
16.1.2;9.1.2 Überzeugen Sie Insider: Champions und Blockierer;234
16.1.3;9.1.3 Identifizieren Sie mögliche Einstiegspunkte;235
16.2;9.2 Wege zum Erfolg;237
16.2.1;9.2.1 Guerilla-Implementierung (Bottom-up);237
16.2.2;9.2.2 Überzeugen Sie das Management (Top-down);237
16.2.3;9.2.3 Holen Sie einen externen Champion;238
16.2.4;9.2.4 Machen Sie Fortschritte sichtbar;238
16.2.5;9.2.5 Streben Sie bestimmte Ziele an;240
16.2.6;9.2.6 Machen Sie sich klar, dass es Hürden geben wird;241
16.3;9.3 Wege zum Misserfolg;242
16.3.1;9.3.1 Mangelnde Triebkraft;242
16.3.2;9.3.2 Mangelnde politische Unterstützung;242
16.3.3;9.3.3 Schlechte Implementierungen und erste Eindrücke;242
16.3.4;9.3.4 Mangelnde Teamunterstützung;243
16.4;9.4 Einflussfaktoren;243
16.5;9.5 Schwierige Fragen und Antworten;245
16.5.1;9.5.1 Wie viel zusätzliche Zeit wird der aktuelle Prozess für das Unit Testing benötigen?;245
16.5.2;9.5.2 Ist mein Job bei der QS in Gefahr wegen des Unit Testing?;247
16.5.3;9.5.3 Woher wissen wir, dass Unit Tests wirklich funktionieren?;247
16.5.4;9.5.4 Gibt es denn einen Beweis, dass Unit Testing hilft?;248
16.5.5;9.5.5 Warum findet die QS immer noch Bugs?;248
16.5.6;9.5.6 Wir haben eine Menge Code ohne Tests: Wo fangen wir an?;249
16.5.7;9.5.7 Wir arbeiten mit mehreren Sprachen: Ist Unit Testing da praktikabel?;249
16.5.8;9.5.8 Was ist, wenn wir eine Kombination aus Soft- und Hardware entwickeln?;250
16.5.9;9.5.9 Wie können wir wissen, dass wir keine Bugs in unseren Tests haben?;250
16.5.10;9.5.10 Mein Debugger zeigt mir, dass mein Code funktioniert: Wozu brauche ich Tests?;250
16.5.11;9.5.11 Müssen wir Code im TDD-Stil schreiben?;250
16.6;9.6 Zusammenfassung;251
17;Kapitel 10: Der Umgang mit Legacy-Code;253
17.1;10.1 Wo soll man mit dem Einbauen der Tests beginnen?;254
17.2;10.2 Bestimmen Sie eine Auswahlstrategie;256
17.2.1;10.2.1 Vor- und Nachteile der Strategie »Einfaches zuerst«;256
17.2.2;10.2.2 Vor- und Nachteile der Strategie »Schwieriges zuerst«;256
17.3;10.3 Schreiben Sie Integrationstests, bevor Sie mit dem Refactoring beginnen;257
17.4;10.4 Wichtige Tools für das Unit Testing von Legacy-Code;258
17.4.1;10.4.1 Abhängigkeiten isolieren Sie leicht mit uneingeschränkten Isolation-Frameworks;259
17.4.2;10.4.2 Verwenden Sie JMockit für Java-Legacy-Code;260
17.4.3;10.4.3 Verwenden Sie Vise beim Refactoring Ihres Java-Codes;262
17.4.4;10.4.4 Verwenden Sie Akzeptanztests, bevor Sie mit dem Refactoring beginnen;263
17.4.5;10.4.5 Lesen Sie das Buch von Michael Feathers zu Legacy-Code;264
17.4.6;10.4.6 Verwenden Sie NDepend, um Ihren Produktionscode zu untersuchen;265
17.4.7;10.4.7 Verwenden Sie ReSharper für die Navigation und das Refactoring des Produktionscodes;265
17.4.8;10.4.8 Spüren Sie Code-Duplikate (und Bugs) mit Simian und TeamCity auf;265
17.5;10.5 Zusammenfassung;266
18;Kapitel 11: Design und Testbarkeit;267
18.1;11.1 Warum sollte ich mir Gedanken um die Testbarkeit in meinem Design machen?;267
18.2;11.2 Designziele für die Testbarkeit;268
18.2.1;11.2.1 Deklarieren Sie Methoden standardmäßig als virtuell;269
18.2.2;11.2.2 Benutzen Sie ein Interface-basiertes Design;270
18.2.3;11.2.3 Deklarieren Sie Klassen standardmäßig als nicht versiegelt;270
18.2.4;11.2.4 Vermeiden Sie es, konkrete Klassen innerhalb von Methoden mit Logik zu instanziieren;270
18.2.5;11.2.5 Vermeiden Sie direkte Aufrufe von statischen Methoden;271
18.2.6;11.2.6 Vermeiden Sie Konstruktoren und statische Konstruktoren, die Logik enthalten;271
18.2.7;11.2.7 Trennen Sie die Singleton-Logik und Singleton-Halter;272
18.3;11.3 Vor- und Nachteile des Designs zum Zwecke der Testbarkeit;273
18.3.1;11.3.1 Arbeitsumfang;274
18.3.2;11.3.2 Komplexität;274
18.3.3;11.3.3 Das Preisgeben von sensiblem IP;274
18.3.4;11.3.4 Manchmal geht’s nicht;275
18.4;11.4 Alternativen des Designs zum Zwecke der Testbarkeit;275
18.4.1;11.4.1 Design-Argumente und Sprachen mit dynamischen Typen;275
18.5;11.5 Beispiel eines schwer zu testenden Designs;277
18.6;11.6 Zusammenfassung;281
18.7;11.7 Zusätzliche Ressourcen;282
19;Anhang A: Tools und Frameworks;285
19.1;A.1 Isolation-Frameworks;285
19.1.1;A.1.1 Moq;286
19.1.2;A.1.2 Rhino Mocks;286
19.1.3;A.1.3 Typemock Isolator;287
19.1.4;A.1.4 JustMock;287
19.1.5;A.1.5 Microsoft Fakes (Moles);287
19.1.6;A.1.6 NSubstitute;288
19.1.7;A.1.7 FakeItEasy;288
19.1.8;A.1.8 Foq;289
19.1.9;A.1.9 Isolator++;289
19.2;A.2 Test-Frameworks;289
19.2.1;A.2.1 Mighty Moose (auch bekannt als ContinuousTests) Continuous Runner;290
19.2.2;A.2.2 NCrunch Continuous Runner;290
19.2.3;A.2.3 Typemock Isolator Test Runner;290
19.2.4;A.2.4 CodeRush Test Runner;290
19.2.5;A.2.5 ReSharper Test Runner;291
19.2.6;A.2.6 TestDriven.NET Runner;291
19.2.7;A.2.7 NUnit GUI Runner;292
19.2.8;A.2.8 MSTest Runner;292
19.2.9;A.2.9 Pex;292
19.3;A.3 Test-APIs;293
19.3.1;A.3.1 MSTest-API – Microsofts Unit-Testing-Framework;293
19.3.2;A.3.2 MSTest für Metro Apps (Windows Store);293
19.3.3;A.3.3 NUnit API;294
19.3.4;A.3.4 xUnit.net;294
19.3.5;A.3.5 Fluent Assertions Helper API;294
19.3.6;A.3.6 Shouldly Helper API;294
19.3.7;A.3.7 SharpTestsEx Helper API;295
19.3.8;A.3.8 AutoFixture Helper API;295
19.4;A.4 IoC-Container;295
19.4.1;A.4.1 Autofac;296
19.4.2;A.4.2 Ninject;297
19.4.3;A.4.3 Castle Windsor;297
19.4.4;A.4.4 Microsoft Unity;297
19.4.5;A.4.5 StructureMap;297
19.4.6;A.4.6 Microsoft Managed Extensibility Framework;297
19.5;A.5 Datenbanktests;298
19.5.1;A.5.1 Verwenden Sie Integrationstests für Ihre Datenschicht;298
19.5.2;A.5.2 Verwenden Sie TransactionScope für ein Rollback der Daten;298
19.6;A.6 Webtests;299
19.6.1;A.6.1 Ivonna;300
19.6.2;A.6.2 Team System Web Test;300
19.6.3;A.6.3 Watir;300
19.6.4;A.6.4 Selenium WebDriver;300
19.6.5;A.6.5 Coypu;301
19.6.6;A.6.6 Capybara;301
19.6.7;A.6.7 JavaScript-Tests;301
19.7;A.7 UI-Tests (Desktop);301
19.8;A.8 Thread-bezogene Tests;302
19.8.1;A.8.1 Microsoft CHESS;302
19.8.2;A.8.2 Osherove.ThreadTester;302
19.9;A.9 Akzeptanztests;302
19.9.1;A.9.1 FitNesse;303
19.9.2;A.9.2 SpecFlow;303
19.9.3;A.9.3 Cucumber;303
19.9.4;A.9.4 TickSpec;304
19.10;A.10 API-Frameworks im BDD-Stil;304
20;Stichwortverzeichnis;305
Einleitung
Eines der größten Projekte, an dem ich mitgearbeitet habe und das schiefgelaufen ist, beinhaltete auch Unit Tests. Das dachte ich zumindest. Ich leitete eine Gruppe von Entwicklern, die an einer Abrechnungssoftware arbeiteten, und wir machten es komplett auf die testgetriebene Weise – wir schrieben zuerst die Tests, dann den Code, die Tests schlugen fehl, wir sorgten dafür, dass sie erfolgreich verliefen, führten ein Refactoring durch und fingen wieder von vorne an. Die ersten paar Monate des Projekts waren großartig. Alles lief gut und wir hatten Tests, die belegten, dass unser Code funktionierte. Aber im Laufe der Zeit änderten sich die Anforderungen. Wir waren also gezwungen, unseren Code zu ändern, um diesen neuen Anforderungen gerecht zu werden, doch als wir das taten, wurden die Tests unzuverlässig und mussten nachgebessert werden. Der Code funktionierte immer noch, aber die Tests, die wir dafür geschrieben hatten, waren so zerbrechlich, dass jede kleine Änderung in unserem Code sie überforderte, auch wenn der Code selbst prima funktionierte. Die Änderung des Codes in einer Klasse oder Methode wurde zu einer gefürchteten Aufgabe, weil wir auch alle damit zusammenhängenden Unit Tests entsprechend anpassen mussten. Schlimmer noch, einige Tests wurden sogar unbrauchbar, weil diejenigen, die sie geschrieben hatten, das Projekt verließen und keiner wusste, wie deren Tests zu pflegen waren oder was sie eigentlich testeten. Die Namen, die wir unseren Unit-Testing-Methoden gaben, waren nicht aussagekräftig genug und wir hatten Tests, die auf anderen Tests aufbauten. Schließlich warfen wir nach weniger als sechs Monaten Projektlaufzeit die meisten der Tests wieder hinaus. Das Projekt war ein erbärmlicher Fehlschlag, weil wir zugelassen hatten, dass die Tests, die wir schrieben, mehr schadeten als nützten. Langfristig brauchten wir mehr Zeit, um sie zu pflegen und zu verstehen, als sie uns einsparten. Also hörten wir auf, sie einzusetzen. Ich machte mit anderen Projekten weiter und dort haben wir unsere Arbeit beim Schreiben der Unit Tests besser erledigt. Ihr Einsatz brachte uns großen Erfolg und sparte eine Menge Zeit beim Debuggen und bei der Integration. Seitdem dieses erste Projekt fehlschlug, trage ich bewährte Vorgehensweisen für das Unit Testing zusammen und wende sie auch im nachfolgenden Projekt an. Im Laufe jedes Projekts, an dem ich arbeite, entdecke ich weitere gute Vorgehensweisen. Zu verstehen, wie man Unit Tests schreibt – und wie man sie wartbar, lesbar und vertrauenswürdig macht –, ist das, wovon dieses Buch handelt. Egal, welche Sprache oder welche integrierte Entwicklungsumgebung (IDE) Sie verwenden. Dieses Buch behandelt die Grundlagen für das Schreiben von Unit Tests, geht dann auf die Grundlagen des Interaction Testings ein und stellt schließlich bewährte Vorgehensweisen für das Schreiben, das Verwalten und das Warten der Unit Tests in echten Projekten vor. Über dieses Buch
Dass man das, was man wirklich lernen möchte, unterrichten sollte, ist das vielleicht Klügste, was ich jemals irgendwen über das Lernen sagen hörte (ich vergaß, wer das war). Das Schreiben und Veröffentlichen der ersten Ausgabe dieses Buches im Jahre 2009 war nicht weniger als eine echte Lehre für mich. Ursprünglich schrieb ich das Buch, weil ich keine Lust mehr hatte, die gleichen Fragen immer wieder zu beantworten. Aber natürlich gab es auch andere Gründe. Ich wollte etwas Neues ausprobieren, ich wollte experimentieren, ich wollte herausfinden, was ich lernen konnte, indem ich ein Buch schrieb – irgendein Buch. Im Bereich Unit Testing war ich gut. Dachte ich. Aber es ist ein Fluch: Je mehr Erfahrung man hat, desto dümmer kommt man sich vor. Es gibt Teile in der ersten Ausgabe, denen ich heute nicht mehr zustimme – bespielsweise, dass sich eine Unit auf eine Methode bezieht. Das ist einfach nicht richtig. Eine Unit ist eine Arbeitseinheit, was ich in Kapitel 1 dieser zweiten Auflage diskutiere. Sie kann so klein sein wie eine Methode oder so groß wie mehrere Klassen (möglicherweise Assemblies). Und wie Sie noch sehen werden, gibt es weitere Dinge, die sich ebenfalls geändert haben. Was neu ist in der zweiten Auflage
In dieser zweiten Auflage habe ich Material über die Unterschiede zwischen beschränkten und unbeschränkten Isolation-Frameworks hinzugefügt. Es gibt ein neues Kapitel 6, das sich mit der Frage beschäftigt, was ein gutes Isolation-Framework ausmacht und wie ein Framework wie Typemock im Inneren funktioniert. Ich verwende RhinoMocks nicht mehr. Lassen Sie die Finger davon. Es ist tot. Zumindest für den Augenblick. Ich benutze NSubstitute für Beispiele zu den Grundlagen von Isolation-Frameworks und ich empfehle auch FakeItEasy. Ich bin immer noch nicht begeistert von MOQ, was ich detaillierter in Kapitel 6 erläutern werde. Dem Kapitel über die Implementation des Unit Testings auf der Organisationsebene habe ich weitere Techniken hinzugefügt. Es gibt eine Reihe von Design-Änderungen im Code, der in diesem Buch abgedruckt ist. Meist habe ich aufgehört, Property Setters zu verwenden, und benutze häufig Constructor Injection. Einige Diskussionen zu den Prinzipien von SOLID habe ich hinzugefügt – aber nur so viel, um Ihnen Appetit auf das Thema zu machen. Die auf das Build bezogenen Teile von Kapitel 7 enthalten ebenfalls neue Informationen. Seit dem ersten Buch habe ich eine Menge zur Build-Automatisierung und zu Mustern gelernt. Ich rate von Setup-Methoden ab und stelle Alternativen vor, um Ihre Test mit der gleichen Funktionalität auszustatten. Ich benutze auch neuere Versionen von Nunit, sodass sich einige der neueren Nunit APIs in diesem Buch geändert haben. Den Teil von Kapitel 10, der sich mit Tools im Hinblick auf Legacy-Code beschäftigt, habe ich aktualisiert. Die Tatsache, dass ich in den letzten drei Jahren neben .NET mit Ruby gearbeitet habe, führte bei mir zu neuen Einsichten in Bezug auf Design und Testbarkeit. Das spiegelt sich in Kapitel 11 wider. Den Anhang zu Werkzeugen und Frameworks habe ich aktualisiert, neue Tools hinzugefügt und alte entfernt. Wer dieses Buch lesen sollte
Dieses Buch ist für jeden geeignet, der Code entwickelt und daran interessiert ist, die besten Methoden für das Unit Testing zu erlernen. Alle Beispiele sind mit Visual Studio in C# geschrieben, weshalb die Beispiele insbesondere für .NET-Entwickler nützlich sein werden. Aber was ich unterrichte, passt genau so gut auf die meisten, wenn nicht auf alle objektorientierten und statisch typisierten Sprachen (VB.NET, Java und C++, um nur ein paar zu nennen). Egal, ob Sie ein Architekt sind, ein Entwickler, ein Teamleiter, ein QS-Mitarbeiter (der Code schreibt) oder ein Anfänger in der Programmierung, dieses Buch wurde für Sie geschrieben. Meilensteine
Wenn Sie noch nie einen Unit Test geschrieben haben, dann ist es am besten, Sie lesen das Buch vom Anfang bis zum Ende, um das komplette Bild zu erhalten. Wenn Sie aber schon Erfahrung haben, dann fühlen Sie sich frei, so in den Kapiteln zu springen, wie es Ihnen gerade passt. Das vorliegende Buch ist in vier Hauptteile gegliedert. Teil I bringt Sie beim Schreiben von Unit Tests von 0 auf 100. Kapitel 1 und 2 beschäftigen sich mit den Grundlagen, wie etwa der Verwendung eines Test-Frameworks (NUnit), und führen die grundlegenden Testattribute ein, wie z. B. [Test] und [TestCase]. Darüber hinaus werden hier auch verschiedene Prinzipien erläutert im Hinblick auf die Assertion, das Ignorieren von Tests, das Testen von Arbeitseinheiten (Unit of Work Testing), die drei Typen von Endergebnissen eines Unit Tests und der drei dazu benötigten Arten von Tests, nämlich Value Tests, State-Based Tests und Interaction Tests. Teil II diskutiert fortgeschrittene Methoden zum Auflösen von Abhängigkeiten: Mock-Objekte, Stubs, Isolation-Frameworks und Muster zum Refactoring Ihres Codes, um diese nutzen zu können. Kapitel 3 stellt das Konzept der Stubs vor und veranschaulicht, wie man sie von Hand erzeugen und benutzen kann. In Kapitel 4 wird das Interaction Testing mit handgeschriebenen Mock-Objekten beschrieben. Kapitel 5 führt diese beiden Konzepte schließlich zusammen und zeigt, wie sie sich mithilfe von Isolation-(Mock-)Frameworks kombinieren lassen und ihre Automatisierung erlauben. Kapitel 6 vertieft das Verständnis für beschränkte und unbeschränkte Isolation-Frameworks und wie sie unter der Haube funktionieren. Teil III beschäftigt sich mit verschiedenen Möglichkeiten, den Testcode zu organisieren, mit Mustern, um ihn auszuführen und seine Strukturen umzubauen (Refactoring), und mit bewährten Methoden zum Schreiben von Tests. In Kapitel 7 werden Testhierarchien vorgestellt und es wird dargestellt, wie Testinfrastruktur-APIs verwendet und wie Tests in den automatisierten Build-Prozess eingebunden werden. Kapitel 7 diskutiert bewährte Vorgehensweisen beim Unit Testing, um wartbare, lesbare und vertrauenswürdige Tests zu entwickeln. Teil IV beschäftigt...