O'Reilly logo

Stay ahead with the world's most comprehensive technology and business learning platform.

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, tutorials, and more.

Start Free Trial

No credit card required

The Art of Unit Testing

Book Description

Dies ist ein umfassendes Handbuch zum Arbeiten mit Unit Tests. Es führt Sie Schritt für Schritt von einfachen Unit Tests bis hin zu Tests, mit denen sich der Code umfangreicher Softwareprojekte überprüfen und analysieren lässt. Das Buch ist für .NET-Entwickler geschrieben, aber Entwickler anderer Sprachen können ebenso von den Inhalten profitieren.

Table of Contents

  1. Impressum
  2. Vorwort zur zweiten Auflage
  3. Vorwort zur ersten Auflage
  4. Einleitung
  5. Teil I: Erste Schritte
  6. Kapitel 1: Die Grundlagen des Unit Testings
    1. 1.1 Unit Testing – Schritt für Schritt definiert
      1. 1.1.1 Die Bedeutung guter Unit Tests​
      2. 1.1.2 Wir alle haben schon Unit Tests geschrieben (irgendwie)
    2. 1.2 Eigenschaften eines »guten« Unit Test​​s
    3. 1.3 Integrationstests​
      1. 1.3.1 Nachteile von nicht automatisierten Integrationstests​ im Vergleich zu automatisierten Unit Tests
    4. 1.4 Was Unit Tests »gut« macht
    5. 1.5 Ein einfaches Unit-Test-Beispiel
    6. 1.6 Testgetriebene Entwicklung​
    7. 1.7 Die drei Schlüsselqualifikationen für erfolgreiches TDD
    8. 1.8 Zusammenfassung
  7. Kapitel 2: Ein erster Unit Test
    1. 2.1 Frameworks für das Unit Testing
      1. 2.1.1 Was Unit-Testing-Frameworks bieten
      2. 2.1.2 Die xUnit-Frameworks
    2. 2.2 Das LogAn-Projekt​ wird vorgestellt
    3. 2.3 Die ersten Schritte mit NUnit
      1. 2.3.1 Die Installation von NUni​t
      2. 2.3.2 Das Laden der Projektmappe
      3. 2.3.3 Die Verwendung der NUnit​-Attribute in Ihrem Code
    4. 2.4 Sie schreiben Ihren ersten Test
      1. 2.4.1 Die Klasse Assert​
      2. 2.4.2 Sie führen Ihren ersten Test mit NUnit aus
      3. 2.4.3 Sie fügen positive Tests hinzu
      4. 2.4.4 Von Rot nach Grün: das erfolgreiche Ausführen der Tests
      5. 2.4.5 Test-Code-Gestaltung
    5. 2.5 Refactoring zu parametrisierten Tests
    6. 2.6 Weitere NUnit​-Attribute
      1. 2.6.1 Aufbau​ und Abbau​
      2. 2.6.2 Auf erwartete Ausnahmen​ prüfen
      3. 2.6.3 Das Ignorieren​ von Tests
      4. 2.6.4 Die fließende Syntax von NUnit
      5. 2.6.5 Das Festlegen der Testkategorie​n
    7. 2.7 Das Testen auf Zustandsänderungen des Systems statt auf Rückgabewerte
    8. 2.8 Zusammenfassung
  8. Teil II: Zentrale Methoden
  9. Kapitel 3: Die Verwendung von Stubs, um Abhängigkeiten aufzulösen
    1. 3.1 Die Stubs werden vorgestellt
    2. 3.2 Die Identifizierung einer Dateisystemabhängigkeit in LogAn
    3. 3.3 Die Entscheidung, wie LogAnalyzer am einfachsten getestet werden kann
    4. 3.4 Design-Refactoring zur Verbesserung der Testbarkeit​
      1. 3.4.1 Extrahiere ein Interface​, um die dahinter liegende Implementierung durch eine andere ersetzen zu können
      2. 3.4.2 Dependency Injection: Injiziere eine Fake-Implementierung​ in die zu testende Unit
      3. 3.4.3 Injiziere einen Fake auf Konstruktor-Ebene (Construktor Injectio​n)
      4. 3.4.4 Simuliere Ausnahmen über Fakes
      5. 3.4.5 Injiziere ein Fake als Property Get oder Set
      6. 3.4.6 Injiziere einen Fake unmittelbar vor einem Methodenaufruf
    5. 3.5 Variationen der Refactoring​-Technik
      1. 3.5.1 Die Verwendung von Extract and Override​, um Fake-Resultate zu erzeugen
    6. 3.6 Die Überwindung des Kapselungsproblems​
      1. 3.6.1 Die Verwendung von internal​ und [InternalsVisibleTo​]
      2. 3.6.2 Die Verwendung des Attributs [Conditiona​l]
      3. 3.6.3 Die Verwendung von #if und #endif zur bedingten Kompilierung​​
    7. 3.7 Zusammenfassung
  10. Kapitel 4: Interaction Testing mit Mock-Objekten
    1. 4.1 Wertbasiertes Testen versus zustandsbasiertes Testen versus Testen versus Interaction Testing
    2. 4.2 Der Unterschied zwischen Mocks​ und Stubs​
    3. 4.3 Ein einfaches manuelles Mock-Beispiel
    4. 4.4 Die gemeinsame Verwendung von Mock​ und Stub​
    5. 4.5 Ein Mock​ pro Test
    6. 4.6 Fake-Ketten​​: Stubs, die Mocks oder andere Stubs erzeugen
    7. 4.7 Die Probleme mit handgeschriebenen Mocks​ und Stubs​
    8. 4.8 Zusammenfassung
  11. Kapitel 5: Isolation-(Mock-Objekt-)Frameworks
    1. 5.1 Warum überhaupt Isolation-Frameworks?
    2. 5.2 Das dynamische Erzeugen eines Fake-Objekts
      1. 5.2.1 Die Einführung von NSubstitute in Ihre Tests
      2. 5.2.2 Das Ersetzen eines handgeschriebenen Fake-Objekts durch ein dynamisches
    3. 5.3 Die Simulation von Fake-Werten
      1. 5.3.1 Ein Mock, ein Stub und ein Ausflug in einen Test
    4. 5.4 Das Testen auf ereignisbezogene Aktivitäten
      1. 5.4.1 Das Testen eines Event Listeners
      2. 5.4.2 Der Test, ob ein Event getriggert wurde
    5. 5.5 Die aktuellen Isolation-Frameworks für .NET
    6. 5.6 Die Vorteile und Fallstricke von Isolation-Frameworks
      1. 5.6.1 Fallstricke, die man bei der Verwendung von Isolation-Frameworks besser vermeidet
      2. 5.6.2 Unlesbarer Testcode
      3. 5.6.3 Die Verifizierung der falschen Dinge
      4. 5.6.4 Die Verwendung von mehr als einem Mock pro Test
      5. 5.6.5 Die Überspezifizierung​ von Tests
    7. 5.7 Zusammenfassung
  12. Kapitel 6: Wir tauchen tiefer ein in die Isolation-Frameworks
    1. 6.1 Eingeschränkte und uneingeschränkte Frameworks
      1. 6.1.1 Eingeschränkte Frameworks
      2. 6.1.2 Uneingeschränkte Frameworks
      3. 6.1.3 Wie Profiler-basierte uneingeschränkte Frameworks arbeiten
    2. 6.2 Werte guter Isolation-Frameworks
    3. 6.3 Eigenschaften, die Zukunftssicherheit und Benutzerfreundlichkeit unterstützen
      1. 6.3.1 Rekursive Fakes​​
      2. 6.3.2 Ignoriere Argumente als Voreinstellung
      3. 6.3.3 Umfangreiches Fälschen
      4. 6.3.4 Nicht striktes Verhalten von Fakes
      5. 6.3.5 Nicht strikte Mocks
    4. 6.4 Isolation-Framework-Design-Antimuster
      1. 6.4.1 Konzept-Konfusion
      2. 6.4.2 Aufnahme und Wiedergabe
      3. 6.4.3 Klebriges Verhalten​​
      4. 6.4.4 Komplexe Syntax​​
    5. 6.5 Zusammenfassung
  13. Teil III: Der Testcode
  14. Kapitel 7: Testhierarchie und Organisation
    1. 7.1 Automatisierte Builds, die automatisierte Tests​ laufen lassen
      1. 7.1.1 Die Anatomie eines Build-Skripts
      2. 7.1.2 Das Anstoßen von Builds und Integration
    2. 7.2 Testentwürfe, die auf Geschwindigkeit und Typ basieren
      1. 7.2.1 Der menschliche Faktor beim Trennen von Unit und Integrationstests
      2. 7.2.2 Die sichere grüne Zone
    3. 7.3 Stellen Sie sicher, dass die Tests zu Ihrer Quellcodekontrolle​ gehören
    4. 7.4 Das Abbilden der Testklassen auf den zu testenden Code
      1. 7.4.1 Das Abbilden von Tests auf Projekte
      2. 7.4.2 Das Abbilden von Tests auf Klassen
      3. 7.4.3 Das Abbilden von Tests auf bestimmte Methoden
    5. 7.5 Querschnittsbelang-Injektion
    6. 7.6 Der Bau einer Test-API für Ihre Applikation
      1. 7.6.1 Die Verwendung von Testklassen-Vererbungsmustern
      2. 7.6.2 Der Entwurf von Test-Hilfsklassen und -Hilfsmethoden
      3. 7.6.3 Machen Sie Ihre API den Entwicklern bekannt
    7. 7.7 Zusammenfassung
  15. Kapitel 8: Die Säulen guter Unit Tests
    1. 8.1 Das Schreiben vertrauenswürdiger Tests
      1. 8.1.1 Die Entscheidung, wann Tests entfernt oder geändert werden
      2. 8.1.2 Vermeiden Sie Logik in Tests
      3. 8.1.3 Testen Sie nur einen Belang
      4. 8.1.4 Trennen Sie Unit Tests von Integrationstests
      5. 8.1.5 Stellen Sie Code-Reviews mit Codeabdeckung sicher
    2. 8.2 Das Schreiben wartbarer Tests
      1. 8.2.1 Das Testen privater oder geschützter Methoden
      2. 8.2.2 Das Entfernen von Duplizitäten
      3. 8.2.3 Die Verwendung von Setup-Methoden in einer wartbaren Art und Weise
      4. 8.2.4 Das Erzwingen der Test-Isolierung
      5. 8.2.5 Vermeiden Sie mehrfache Asserts für unterschiedliche Belange
      6. 8.2.6 Der Vergleich von Objekten
      7. 8.2.7 Vermeiden Sie eine Überspezifizierung​ der Tests
    3. 8.3 Das Schreiben lesbarer Tests
      1. 8.3.1 Die Benennung der Unit Tests
      2. 8.3.2 Die Benennung der Variablen
      3. 8.3.3 Benachrichtigen​ Sie sinnvoll
      4. 8.3.4 Das Trennen der Asserts von den Aktionen
      5. 8.3.5 Aufbauen und Abreißen
    4. 8.4 Zusammenfassung
  16. Teil IV: Design und Durchführung
  17. Kapitel 9: Die Integration von Unit Tests in die Organisation
    1. 9.1 Schritte, um ein Agent des Wandels zu werden
      1. 9.1.1 Seien Sie auf die schweren Fragen vorbereitet
      2. 9.1.2 Überzeugen Sie Insider​: Champions​ und Blockierer
      3. 9.1.3 Identifizieren Sie mögliche Einstiegspunkte
    2. 9.2 Wege zum Erfolg
      1. 9.2.1 Guerilla-Implementierung​ (Bottom-up​)
      2. 9.2.2 Überzeugen Sie das Management (Top-down)
      3. 9.2.3 Holen Sie einen externen Champion
      4. 9.2.4 Machen Sie Fortschritte sichtbar
      5. 9.2.5 Streben Sie bestimmte Ziele an
      6. 9.2.6 Machen Sie sich klar, dass es Hürden geben wird
    3. 9.3 Wege zum Misserfolg
      1. 9.3.1 Mangelnde Triebkraft
      2. 9.3.2 Mangelnde politische Unterstützung
      3. 9.3.3 Schlechte Implementierungen und erste Eindrücke
      4. 9.3.4 Mangelnde Teamunterstützung
    4. 9.4 Einflussfaktoren
    5. 9.5 Schwierige Fragen und Antworten
      1. 9.5.1 Wie viel zusätzliche Zeit wird der aktuelle Prozess für das Unit Testing benötigen?
      2. 9.5.2 Ist mein Job bei der QS in Gefahr wegen des Unit Testing?
      3. 9.5.3 Woher wissen wir, dass Unit Tests wirklich funktionieren?
      4. 9.5.4 Gibt es denn einen Beweis, dass Unit Testing hilft?
      5. 9.5.5 Warum findet die QS​ immer noch Bugs?
      6. 9.5.6 Wir haben eine Menge Code ohne Tests: Wo fangen wir an?
      7. 9.5.7 Wir arbeiten mit mehreren Sprachen: Ist Unit Testing da praktikabel?
      8. 9.5.8 Was ist, wenn wir eine Kombination aus Soft- und Hardware entwickeln?
      9. 9.5.9 Wie können wir wissen, dass wir keine Bugs in unseren Tests haben?
      10. 9.5.10 Mein Debugger zeigt mir, dass mein Code funktioniert: Wozu brauche ich Tests?
      11. 9.5.11 Müssen wir Code im TDD-Stil schreiben?
    6. 9.6 Zusammenfassung
  18. Kapitel 10: Der Umgang mit Legacy-Code
    1. 10.1 Wo soll man mit dem Einbauen der Tests beginnen?
    2. 10.2 Bestimmen Sie eine Auswahlstrategie
      1. 10.2.1 Vor- und Nachteile der Strategie »Einfaches zuerst​«
      2. 10.2.2 Vor- und Nachteile der Strategie »Schwieriges zuerst​«
    3. 10.3 Schreiben Sie Integrationstests, bevor Sie mit dem Refactoring beginnen
    4. 10.4 Wichtige Tools für das Unit Testing von Legacy-Code
      1. 10.4.1 Abhängigkeiten isolieren Sie leicht mit uneingeschränkten Isolation-Frameworks
      2. 10.4.2 Verwenden Sie JMockit für Java-Legacy-Code
      3. 10.4.3 Verwenden Sie Vise​ beim Refactoring Ihres Java-Codes
      4. 10.4.4 Verwenden Sie Akzeptanztests, bevor Sie mit dem Refactoring beginnen
      5. 10.4.5 Lesen Sie das Buch von Michael Feathers zu Legacy-Code
      6. 10.4.6 Verwenden Sie NDepend, um Ihren Produktionscode zu untersuchen
      7. 10.4.7 Verwenden Sie ReSharper für die Navigation und das Refactoring des Produktionscodes
      8. 10.4.8 Spüren Sie Code-Duplikate (und Bugs) mit Simian und TeamCity auf
    5. 10.5 Zusammenfassung
  19. Kapitel 11: Design und Testbarkeit
    1. 11.1 Warum sollte ich mir Gedanken um die Testbarkeit in meinem Design​ machen?
    2. 11.2 Designziele für die Testbarkeit
      1. 11.2.1 Deklarieren Sie Methoden standardmäßig als virtuell
      2. 11.2.2 Benutzen Sie ein Interface-basiertes Design
      3. 11.2.3 Deklarieren Sie Klassen standardmäßig als nicht versiegelt
      4. 11.2.4 Vermeiden Sie es, konkrete Klassen innerhalb von Methoden mit Logik zu instanziieren
      5. 11.2.5 Vermeiden Sie direkte Aufrufe von statischen Methoden
      6. 11.2.6 Vermeiden Sie Konstruktoren und statische Konstruktoren, die Logik enthalten
      7. 11.2.7 Trennen Sie die Singleton-Logik und Singleton-Halter
    3. 11.3 Vor- und Nachteile des Designs zum Zwecke der Testbarkeit
      1. 11.3.1 Arbeitsumfang
      2. 11.3.2 Komplexität
      3. 11.3.3 Das Preisgeben von sensiblem IP
      4. 11.3.4 Manchmal geht’s nicht
    4. 11.4 Alternativen des Designs zum Zwecke der Testbarkeit
      1. 11.4.1 Design-Argumente und Sprachen mit dynamischen Typen
    5. 11.5 Beispiel eines schwer zu testenden Designs
    6. 11.6 Zusammenfassung
    7. 11.7 Zusätzliche Ressourcen
  20. Anhang A: Tools und Frameworks
    1. A.1 Isolation-Frameworks
      1. A.1.1 Moq
      2. A.1.2 Rhino Mocks
      3. A.1.3 Typemock Isolator
      4. A.1.4 JustMock
      5. A.1.5 Microsoft Fakes (Moles)
      6. A.1.6 NSubstitute
      7. A.1.7 FakeItEasy
      8. A.1.8 Foq
      9. A.1.9 Isolator++
    2. A.2 Test-Frameworks
      1. A.2.1 Mighty Moose (auch bekannt als ContinuousTests) Continuous Runner
      2. A.2.2 NCrunch Continuous Runner
      3. A.2.3 Typemock Isolator Test Runner
      4. A.2.4 CodeRush Test Runner
      5. A.2.5 ReSharper Test Runner
      6. A.2.6 TestDriven.NET Runner
      7. A.2.7 NUnit GUI Runner
      8. A.2.8 MSTest Runner
      9. A.2.9 Pex
    3. A.3 Test-APIs
      1. A.3.1 MSTest-API – Microsofts Unit-Testing-Framework
      2. A.3.2 MSTest für Metro Apps (Windows Store)
      3. A.3.3 NUnit API
      4. A.3.4 xUnit.net
      5. A.3.5 Fluent Assertions Helper API
      6. A.3.6 Shouldly Helper API
      7. A.3.7 SharpTestsEx Helper API
      8. A.3.8 AutoFixture Helper API
    4. A.4 IoC-Container
      1. A.4.1 Autofac
      2. A.4.2 Ninject
      3. A.4.3 Castle Windsor
      4. A.4.4 Microsoft Unity
      5. A.4.5 StructureMap
      6. A.4.6 Microsoft Managed Extensibility Framework
    5. A.5 Datenbanktests
      1. A.5.1 Verwenden Sie Integrationstests für Ihre Datenschicht
      2. A.5.2 Verwenden Sie TransactionScope für ein Rollback der Daten
    6. A.6 Webtests
      1. A.6.1 Ivonna
      2. A.6.2 Team System Web Test
      3. A.6.3 Watir
      4. A.6.4 Selenium WebDriver
      5. A.6.5 Coypu
      6. A.6.6 Capybara
      7. A.6.7 JavaScript-Tests
    7. A.7 UI-Tests (Desktop)
    8. A.8 Thread-bezogene Tests
      1. A.8.1 Microsoft CHESS
      2. A.8.2 Osherove.ThreadTester
    9. A.9 Akzeptanztests
      1. A.9.1 FitNesse
      2. A.9.2 SpecFlow
      3. A.9.3 Cucumber
      4. A.9.4 TickSpec
    10. A.10 API-Frameworks im BDD-Stil