SlideShare ist ein Scribd-Unternehmen logo
Fortgeschrittene Techniken
der Testgetriebenen Entwicklung
  JAX Powerworkshop, 23.04.2007



     Tammo Freese, Johannes Link
Agenda

• Testgetriebene Entwicklung im Überblick
• Akzeptanztests mit FIT
• Unit Tests mit JUnit/Mockobjekte mit EasyMock


• Legacy Code und Code Coverage
• Testen von GUIs und Web-Applikationen
• Testen mit Skriptsprachen
• Diskussion
Motivation

• Software hat Geschäftswert durch zwei Qualitäten
   • Funktionale Qualität
       (Funktionalität, Fehlerfreiheit)
   •   Strukturelle Qualität
       (Design/Codestruktur für Weiterentwicklung)
• Hinzufügen neuer Funktionalität
  gefährdet funktionale und strukturelle Qualität
• Verbesserung der strukturellen Qualität
  gefährdet die funktionale Qualität
Testgetriebene Entwicklung

• Testgetriebene Programmierung:
  Motiviere jede Verhaltensänderung am Code
 durch einen automatisierten Test
 (ständige Absicherung der funktionalen Qualität)
• Refactoring:
  Vereinfache das Code-Design soweit wie möglich
 (funktionale Qualität ist durch Tests abgesichert)
• (Häufige Integration:
  Integriere den Code so häufig wie nötig)
Entwickler schreiben Unit Tests

• testen Komponenten des Systems in Isolation
• geben uns konkretes Feedback
• ermöglichen sichere Änderungen
• sichern Erhalt der vorhandenen Funktionalität
• müssen bei jeder Integration zu 100% laufen


• können funktionale Tests auf Systemebene
  nicht ersetzen!
Kunden spezifizieren Akzeptanztests

• testen das System überwiegend als Ganzes
• geben unseren Kunden Vertrauen
  in die gelieferte Software
• klären die Anforderungen
  frühzeitig an konkreten Beispielen
• machen den Projektfortschritt sichtbar
• müssen vom Kunden erstellt und gepflegt
  werden können
• Unsere Aufgabe ist es, den entsprechenden
  Rahmen für ihre Automatisierung zu schaen!
Akzeptanztests mit FIT

• FIT: Framework for Integrated Test
• Zum Schreiben und Ausführen automatischer
  Akzeptanztests
• Testdaten werden tabellarisch erstellt
  (in HTML, mit Excel oder im Wiki)
• Anbindung ans System in Java
• Portierung für aktuelle Sprachen verfügbar
• http://fit.c2.com
Drei Fixture-Klassen

• ColumnFixture testet Ein-/Ausgabewertemengen.
• ActionFixture spielt ein Benutzerszenario durch
  und ist deshalb gut für GUI-orientierte Tests
  geeignet.
• RowFixture prüft eine Ergebnismenge
  von Objekten mit ihren Attributen.
Column Fixture (1)
Column Fixture (2)

import fit.ColumnFixture;
public class AccountTransferFixture extends ColumnFixture {
           public String sourceAccount;
	

       public String targetAccount;
	

       public double amountTransferred;
	

           public boolean wasTransactionSuccessful()
    	

       throws AccountException {
	

           return false;
	

       }
}
Action Fixture (1)
Action Fixture (2)
import fit.ActionFixture;
public class AccountAdministrationFixture
  extends ActionFixture {
       public void newAccount() {}
	

   public void customerName(String name) {}
	

   public String accountNumber() {
	

   	

   return 0;
	

   }
	

   public void deposit(double money)
	

   	

   throws AccountException {
	

   }
	

   public double balance() {
	

   	

   return 0;
	

   }
}
Row Fixture (1)




public class AccountListingItem {
	

 public String accountNumber;
	

 public double balance() {
	

 	

   return 0;
	

 }	

	

 public String customerName() {
	

 	

   return dummy;
	

 }
}
Row Fixture (2)

import fit.RowFixture;
public class AccountListingFixture extends RowFixture {
	

   public Object[] query() throws Exception {
	

   	

   List result = new ArrayList();
	

   	

   return result.toArray();
	

   }
	

   public Class getTargetClass() {
	

   	

   return AccountListingItem.class;
	

   }
}
Domänenspezifische Fixtures

• wenn keine Fixture-Grundart so richtig passt
• Erweiterungen von fit.Fixture über Hook-
  Methoden:
   •   doTables(Parse tables)
   •   doTable(Parse table)
   •   doRows(Parse rows)
   •   doRow(Parse row)
   •   doCells(Parse cells)
   •   doCell(Parse cell, int index)
Übung 1:
Akzeptanztestgetriebene Entwicklung
• Bringen Sie die Testfälle in
  acceptance-tests/RichCalc.html
 schrittweise zum laufen!


• (TaschenrechnerFixture.java
  ist eine ColumnFixture)
Nachlese Übung 1

• Probleme bei akzeptanztestgetriebener
  Entwicklung
    • (Zu) große Schritte: Es dauert oft zu lange,
      einen Test auf grün zu bringen
   • Keine Möglichkeit, Design zu erzwingen
   • Keine Möglichkeit, Module isoliert ins Leben zu testen
   • Kombinatorische Explosion
• Lösung: Unit Tests
    • Viele kleine Unit Tests schreiben
    • Jeden Akzeptanztest schrittweise erfüllen
JUnit - Testframework für Java

• Java-Framework zum Schreiben und Ausführen
  automatischer Unit Tests
• Tests werden in Java codiert
• Ist auch für zahlreiche andere
  Programmiersprachen erhältlich
• http://junit.org
Beispiel: Test

import org.junit.Test;
import static org.junit.Assert.*;
public class EuroTest {
    @Test
    public void cents() {
      Euro two = new Euro(2.00);
        assertEquals(200, two.getCents());
    }
}
Anatomie eines Testfallklasse

• Testfallmethoden @Test public void ...()
• Verwendung der statisch importierten Methoden
  assert...() und fail()
• Fehlschlag von assert...() beendet den Testfall
• Instanzvariablen für Testobjekte
• @Before public void ...()
  zum Aufbau von Testobjekten und Testressourcen
• @After public void ...()
  zur Ressourcenfreigabe
Beispiel: Test Suite

import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;


@RunWith(value = Suite.class)
@SuiteClasses( { CalculatorTest.class })
public class AllTests {
}
Eclipse: JUnit Testrunner
Test/Code/Refactor – Zyklus




JUnit: Failure   JUnit: OK
Test/Code/Refactor – Schritte

• grün-rot: Schreibe einen Test, der zunächst
  fehlschlagen sollte. Schreibe gerade soviel Code,
  dass der Test fehlschlägt.
• rot-grün: Schreibe gerade soviel Code, dass alle
  Tests laufen.
• grün-grün: Eliminiere Duplikation und andere
  üble Codegerüche.
Programmierzug grün - rot

• Programming by Intention:
  Der Test verwendet die zu testende Funktion,
  als wäre sie schon realisiert.
• Die Klassenschnittstelle wird im Test
  aus der Perspektive eines Verwenders entworfen.
• Jeder Test geht einen kleinen Schritt.
• Den Test zunächst fehlschlagen zu sehen,
  testet den Test selbst.
Programmierzug rot - grün

• Nur soviel Code schreiben, wie die Tests
  erfordern.
• Mehr wäre weder durch die Tests spezifiziert,
  noch abgesichert.
• Erst weitere Tests beweisen, dass die Lösung
  eventuell noch zu einfach ist.
Refactoringzug grün - grün

• Eliminierung von Duplikation!
• Verbesserungen am Design des Programms, ohne
  sein beobachtbares Verhalten zu ändern,
   • um die Verständlichkeit zu erhöhen
   • um Designschwächen zu beheben
   • um die Änderbarkeit zu erhalten.
Strikte Unit Tests

• Ein Unit Test soll eine Klasse
  oder ein Klassenteam in Isolation testen.
• Probleme:
   •   Programmeinheiten arbeiten nicht isoliert.
   •   Aufbau der Testumgebung ist oft aufwändig.
   •   Testen von Ausnahmesituationen
   •   langsame Tests bei Überschreiten der Systemgrenzen
Isoliertes Testen

• Für die Dauer der Tests ersetzen wir
  Abhängigkeiten zu mitwirkenden
  Programmeinheiten durch die Einführung
  einfacher Attrappen. 
• Vorteile:
   • Tests laufen schnell.
   • Auftretende Fehler sind leicht zu lokalisieren.
   • Notwendige Testkombinatorik ist kleiner
     als beim Testen mehrerer Objekte.
Isoliertes Testen
Mock-Objekte

• Ersetzen von der zu testenden Unit verwendeten
  Klassen oder Schnittstellen während des Tests
• Vorgehen:
  • Verhalten und Erwartungen spezifizieren
  • Unit unter Verwendung des Mockobjekts testen
  • korrekte Verwendung verifizieren
EasyMock – Dynamische Mock-Objekte

• Erzeugung eines Mock-Objekts „on the fly“:
   • MyInterface mock =
      createMock(MyInterface.class);


• Aufzeichnen des erwarteten Verhaltens:
   • expect(mock.myMethod(42))andReturn(Y);
    replay(mock);


• Verifikation der Verwendung des Verhaltens:
   • verify(mock);

• http://easymock.org/
Systemgrenzen im Test

• Dummies und Mocks:
  • Was wir zur Isolation innerhalb des Systems verwenden,
      funktioniert auch an Systemgrenzen.
• Bei komplexen Systemgrenzen:
  •   Fassade/Adapter zur zusätzlichen Indirektion einführen
  •   Testen vom System zu Fassade/Adapter
  •   Testen von Fassade/Adapter zur Systemgrenze
  •   funktionale Tests testen das Zusammenspiel
Übung 2: Isolierte Unit Tests

• Bringen Sie die Testfälle in
  acceptance-tests/RichCalc.html
 schrittweise zum laufen!


• Diesmal aber:
   • Schreiben Sie Unit Tests für die Akzeptanztests
   • Setzen Sie Mockobjekte ein, falls nötig
   • Startlinie: calculator.unittests.CalculatorTest
Code Coverage

• Wie gut sind unsere Tests?
• Wie groß ist die Abdeckung des Codes durch
  unsere Tests?
   • http://www.cenqua.com/clover/
   • http://works.dgic.co.jp/djunit/
   • http://www.eclemma.org/
• Welche Code-Änderungen werden durch unsere
  Tests entdeckt?

   • http://jester.sourceforge.net/
• Metriken als Spiegel der Gewohnheit
Testen von Legacy Code

• Legacy Code ist Code ohne automatisierte Tests!


• Michael Feathers:
  „Code without tests is bad code. It doesn't matter
  how well written it is [...] With tests, we can
  change the behavior of our code quickly and
  verifiably. Without them, we really don't know if
  our code is getting better or worse.“
Legacy Code Dilemma

• Um Software sicher zu ändern,
  benötigen wir automatisierte Tests.
• Um automatisierte Tests zu schreiben,
  müssen wir die Software ändern.


• Refactoring ohne Tests unumgänglich
Testen von bestehendem Code

• Änderung des bestehenden Systems
  •   neue Features
  •   Entfernen von Bugs
  •   Designverbesserungen
  •   Optimierungen



• Vergrößerung der Testabdeckung
  • Testgetriebene Entwicklung
  • Charakterisierende Tests
  • Integrationstests
Störende Abhängigkeiten

• Eine Klasse lässt sich nicht instanzieren
• Eine Methode lässt sich nicht ausführen
• Das Testergebnis lässt sich nicht ermitteln
Vorgehen

1. Identifiziere Änderungspunkte
2. Finde Testpunkte
3. Brich Abhängigkeiten
4. Schreibe automatisierte Tests
5. Mache Änderung
6. Räume auf (Refactoring)
Werkzeugkasten

• Automatisierte Refactorings
• JUnit Test-Framework
• Mock-Objekte als Attrappen
• Framework for Integrated Test (FIT)
• Aspektorientierte Programmierung
Einschleusen von Mocks

• als Parameter
• über testbare Unterklasse
• mittels Überlagerung im Klassenpfad
• mit aspektorientierter Programmierung
• in C/C++ auch über Linker und Präprozessor


• Jedes Testproblem lässt sich über eine weitere
  Indirektion lösen
Meine Klasse lehnt sich
             gegen den Test auf

• Ursachen:
   • Klasse kann nicht instanziert werden
   • Hinderliche Konstruktor-Parameter
   • Konstruktor hat Seiteneekte
• Techniken:
   • Extrahiere und überschreibe Methode
   • Extrahiere Interface
   • Parametrisiere Konstruktor
Extrahiere und Überschreibe (1)
                     public class A {
public class A {
                       public A() {
  public A() {
                         B b = makeB();
    B b = new B();
                         b.doStuff();
    b.doStuff();
                         ...
    ...
                       }
  }
                       protected B makeB() {
}
                        return new B();
                       }
                     }
Extrahiere und Überschreibe (2)

public class TestableA extends A {
  protected B makeB() {
    return new DummyB();
  }
}

public class DummyB extends B {
  public void doStuff() {
  }
}
Extrahiere Interface
                          public class A {
public class A {
                            public A() {
  public A() {
                              IB b = makeB();
    B b = makeB();
                              b.doStuff();
    b.doStuff();
                              ...
    ...
                            }
  }
                            protected IB makeB() {
  protected B makeB() {
                              return new B();
    return new B();
                            }
  }
                          }
}
Parametrisiere Konstruktor
                      public class A {
public class A {
                        private IB b;
  public A() {
                        public A(IB b) {
    IB b = makeB();
                          this.b = b;
    b.doStuff();
                          b.doStuff();
    ...
                          ...
  }
                        }
}
                        public A() {
                          this(new B());
                        }
                      }
Weitere Techniken

• Abzweigende Methode
• Abzweigende Klasse
• Statisch gemachte Methoden
• Primitivere Parametertypen
• Führe statischen Setter ein
• Führe delegierende Instanz ein
• Ersetze Singleton durch direkte Abhängigkeit
• Extrahiere Methoden
• Extrahiere Methodenobjekt
Verbesserungen über die Zeit

• Viele der Techniken machen das Design zunächst
  einmal hässlicher
• Durch die ersten installierten Tests sind kleine
  Verbesserungen möglich
• Kleine Verbesserungen lassen weitere
  Refactoringkandidaten erkennen


• Schrittweise zu evolutionärem Design
Testen von GUIs und Web-Applikationen

 • Wichtigster Grundsatz: Keine Logik im View
 • Entwurfsmuster zur Trennung von Präsentation
   und Geschäftslogik:
    • Application Facade
    • Model View Presenter
Application Facade




               interface
        BookSearchFacade
                                               BookSearchDialog
searchTitles(searchExpression:String) : List




                  Book

                Title
                Author
Application Facade mit Observer
                                                            interface
                                                            Observer

                                                       changeOccurred()



                                                  implements
                  interface
           BookSearchFacade
                                                      BookSearchDialog
   searchTitles(searchExpression:String) : List
   registerObserver(observer: Observer)
                                                    changeOccurred()




                     Book

                   Title
                   Author
Model View Presenter


           interface                 interface
      BookSearchView              BookSearchPresenter

     displayList(books:List)    search (searchExpression:String)


implements
                               implements


      BookSearchDialog                BookSearcher
    displayList(books:List)    search (searchExpression:String)
Testen mit Skriptsprachen

• Dynamisch typisierte Skriptsprachen können das
  Testen vereinfachen
• Beispiel Groovy:
   •   Alle Java-Features und Bibliotheken verfügbar
   •   Typisierung ist optional
   •   „Duck-Typing“ ist möglich
   •   Einfache Syntax für Blocks und Iteratoren
Groovy: Vereinfachte Syntax

• Viele Elemente optional:
    • public, Typisierung, Parameterklammern, Semikolon


class CalculatorTest extends GroovyTestCase {

 private calculator

 void setUp() {

 
 calculator = new Calculator()
      ...

}

 void testDisplayThreeDigits() {

 
 checkDisplay '1', '5', '9'

}
   def checkDisplay(String[] buttons) {
      ...

}
Groovy: Closures und Collections

• Einfache Blocksyntax
• Mächtige Collections
• Iteratoren mittels Blöcken

def printer = { line - println line }
printer('Test')

def buttons = [1, 2, 3, 4].reverse()
def displayText = 
buttons.each {

 displayText += it
}
assert displayText == 4321
Groovy: Dynamisch typisierte Objekte

• „Anonyme“ Objekte on the fly
def display = {assert it == displayText} as IDisplay

def display = [display: {println it},


             enableDecimalSeparatorKey: { ... },


             disableDecimalSeparatorKey: { ... }
              ] as IDisplay
Übung 3: Wie es euch gefällt

• Variante 1: Schreiben Sie mit Hilfe von Jemmy eine
  Taschenrechner-Fixture, die direkt die Swing-GUI
  bedient
• Variante 2: Erweitern Sie die Groovy-Testsuite im
  Package groovy.calculator.unittests

• Variante 3: Erweitern Sie GUI und GUI-Tests:
  public interface IDisplay {
  
   void display(String toDisplay);
  
   void disableDecimalSeparatorKey();
  
   void enableDecimalSeparatorKey();
  }
Fragen  Diskussion
Referenzen

• Michael Feathers: Working Eectively with Legacy
  Code. Prentice Hall, 2004.
• Johannes Link: Softwaretests mit JUnit -
  Techniken der testgetriebenen Entwicklung.
  Dpunkt-Verlag, 2005.
• Rick Mugridge, Ward Cunningham: Fit for
  Developing Software. Prentice Hall, 2005.
• Frank Westphal: Testgetriebene Entwicklung mit
  JUnit  FIT. Dpunkt-Verlag, 2005.

Weitere ähnliche Inhalte

Was ist angesagt?

Feige sein! Testen im Java-EE-Umfeld
Feige sein! Testen im Java-EE-UmfeldFeige sein! Testen im Java-EE-Umfeld
Feige sein! Testen im Java-EE-Umfeldgedoplan
 
IPC 2015 Zend Framework 3 Reloaded
IPC 2015 Zend Framework 3 ReloadedIPC 2015 Zend Framework 3 Reloaded
IPC 2015 Zend Framework 3 ReloadedRalf Eggert
 
Was ist neu in Java 6, 7, 8, ...
Was ist neu in Java 6, 7, 8, ...Was ist neu in Java 6, 7, 8, ...
Was ist neu in Java 6, 7, 8, ...Andreas Schreiber
 
Testing untestable code - PHPUGFFM 01/11
Testing untestable code - PHPUGFFM 01/11Testing untestable code - PHPUGFFM 01/11
Testing untestable code - PHPUGFFM 01/11Stephan Hochdörfer
 
2009 03 17 Spring101
2009 03 17 Spring1012009 03 17 Spring101
2009 03 17 Spring101gueste4be40
 
Performance trotz Entity Framwork
Performance trotz Entity FramworkPerformance trotz Entity Framwork
Performance trotz Entity FramworkAndré Krämer
 
Speeding up Java Persistence
Speeding up Java PersistenceSpeeding up Java Persistence
Speeding up Java Persistencegedoplan
 
Celery - eine asynchrone Task Queue (nicht nur) für Django
Celery - eine asynchrone Task Queue (nicht nur) für DjangoCelery - eine asynchrone Task Queue (nicht nur) für Django
Celery - eine asynchrone Task Queue (nicht nur) für DjangoMarkus Zapke-Gründemann
 
Java Persistence 2.0
Java Persistence 2.0Java Persistence 2.0
Java Persistence 2.0gedoplan
 
Entity Framework hinter den Kulissen
Entity Framework hinter den KulissenEntity Framework hinter den Kulissen
Entity Framework hinter den KulissenAndré Krämer
 
Angular von 0 auf 100
Angular von 0 auf 100Angular von 0 auf 100
Angular von 0 auf 100Yvette Teiken
 
Feige sein
Feige seinFeige sein
Feige seingedoplan
 

Was ist angesagt? (15)

Feige sein! Testen im Java-EE-Umfeld
Feige sein! Testen im Java-EE-UmfeldFeige sein! Testen im Java-EE-Umfeld
Feige sein! Testen im Java-EE-Umfeld
 
Testing untestable code - DCHH
Testing untestable code - DCHHTesting untestable code - DCHH
Testing untestable code - DCHH
 
IPC 2015 Zend Framework 3 Reloaded
IPC 2015 Zend Framework 3 ReloadedIPC 2015 Zend Framework 3 Reloaded
IPC 2015 Zend Framework 3 Reloaded
 
Was ist neu in Java 6, 7, 8, ...
Was ist neu in Java 6, 7, 8, ...Was ist neu in Java 6, 7, 8, ...
Was ist neu in Java 6, 7, 8, ...
 
Testing tools
Testing toolsTesting tools
Testing tools
 
Testing untestable code - PHPUGFFM 01/11
Testing untestable code - PHPUGFFM 01/11Testing untestable code - PHPUGFFM 01/11
Testing untestable code - PHPUGFFM 01/11
 
2009 03 17 Spring101
2009 03 17 Spring1012009 03 17 Spring101
2009 03 17 Spring101
 
Performance trotz Entity Framwork
Performance trotz Entity FramworkPerformance trotz Entity Framwork
Performance trotz Entity Framwork
 
T3ak12 extbase
T3ak12 extbaseT3ak12 extbase
T3ak12 extbase
 
Speeding up Java Persistence
Speeding up Java PersistenceSpeeding up Java Persistence
Speeding up Java Persistence
 
Celery - eine asynchrone Task Queue (nicht nur) für Django
Celery - eine asynchrone Task Queue (nicht nur) für DjangoCelery - eine asynchrone Task Queue (nicht nur) für Django
Celery - eine asynchrone Task Queue (nicht nur) für Django
 
Java Persistence 2.0
Java Persistence 2.0Java Persistence 2.0
Java Persistence 2.0
 
Entity Framework hinter den Kulissen
Entity Framework hinter den KulissenEntity Framework hinter den Kulissen
Entity Framework hinter den Kulissen
 
Angular von 0 auf 100
Angular von 0 auf 100Angular von 0 auf 100
Angular von 0 auf 100
 
Feige sein
Feige seinFeige sein
Feige sein
 

Andere mochten auch (20)

Keynote zu einem Panel bei den Medientagen 2006
Keynote zu einem Panel bei den Medientagen 2006Keynote zu einem Panel bei den Medientagen 2006
Keynote zu einem Panel bei den Medientagen 2006
 
Was gehört zur Ausbildungsreife
Was gehört zur AusbildungsreifeWas gehört zur Ausbildungsreife
Was gehört zur Ausbildungsreife
 
Gruppenarbeit demographie
Gruppenarbeit demographieGruppenarbeit demographie
Gruppenarbeit demographie
 
Renaissance der Corporate Blogs
Renaissance der Corporate BlogsRenaissance der Corporate Blogs
Renaissance der Corporate Blogs
 
Automated Web 2.0 Testing
Automated Web 2.0 TestingAutomated Web 2.0 Testing
Automated Web 2.0 Testing
 
Internationales System nach 1917 (Teil 1)
Internationales System nach 1917 (Teil 1)Internationales System nach 1917 (Teil 1)
Internationales System nach 1917 (Teil 1)
 
XP Day Germany 2006 - Keynote
XP Day Germany 2006 - KeynoteXP Day Germany 2006 - Keynote
XP Day Germany 2006 - Keynote
 
Maennerweinen 1
Maennerweinen 1Maennerweinen 1
Maennerweinen 1
 
Gruppenarbeit zum Lernerfolg
Gruppenarbeit zum LernerfolgGruppenarbeit zum Lernerfolg
Gruppenarbeit zum Lernerfolg
 
Edelman Digital in Deutschland
Edelman Digital in DeutschlandEdelman Digital in Deutschland
Edelman Digital in Deutschland
 
Massenhafte Medien statt Massenmedien
Massenhafte Medien statt MassenmedienMassenhafte Medien statt Massenmedien
Massenhafte Medien statt Massenmedien
 
Wennmaneinmalfremdgeht
WennmaneinmalfremdgehtWennmaneinmalfremdgeht
Wennmaneinmalfremdgeht
 
Define
DefineDefine
Define
 
Filter setzen. Überleben in Informationsfluten
Filter setzen. Überleben in InformationsflutenFilter setzen. Überleben in Informationsfluten
Filter setzen. Überleben in Informationsfluten
 
Adam und Eva
Adam und EvaAdam und Eva
Adam und Eva
 
Papagei
PapageiPapagei
Papagei
 
Podpimp Tweetacademy 291009 Handout2
Podpimp  Tweetacademy 291009  Handout2Podpimp  Tweetacademy 291009  Handout2
Podpimp Tweetacademy 291009 Handout2
 
Wer Soll Hier Fahren
Wer Soll Hier FahrenWer Soll Hier Fahren
Wer Soll Hier Fahren
 
Hoeflich 11
Hoeflich 11Hoeflich 11
Hoeflich 11
 
Testgetriebene Softwareentwicklung
Testgetriebene SoftwareentwicklungTestgetriebene Softwareentwicklung
Testgetriebene Softwareentwicklung
 

Ähnlich wie AdvancedTdd

Best Practices für TDD in JavaScript
Best Practices für TDD in JavaScriptBest Practices für TDD in JavaScript
Best Practices für TDD in JavaScriptSebastian Springer
 
Unit testing mit Javascript
Unit testing mit JavascriptUnit testing mit Javascript
Unit testing mit Javascriptjoergreichert
 
Einführung Vorgehensmodelle und Agile Software Entwicklung
Einführung Vorgehensmodelle und Agile Software EntwicklungEinführung Vorgehensmodelle und Agile Software Entwicklung
Einführung Vorgehensmodelle und Agile Software EntwicklungChristian Baranowski
 
Softwarequalitätssicherung mit Continuous Integration Tools
Softwarequalitätssicherung mit Continuous Integration ToolsSoftwarequalitätssicherung mit Continuous Integration Tools
Softwarequalitätssicherung mit Continuous Integration ToolsGFU Cyrus AG
 
Wjax integrationsprojekte auf dem weg zur continuous delivery 2011 11-10
Wjax integrationsprojekte auf dem weg zur continuous delivery 2011 11-10Wjax integrationsprojekte auf dem weg zur continuous delivery 2011 11-10
Wjax integrationsprojekte auf dem weg zur continuous delivery 2011 11-10Ralf Sigmund
 
Gradle - Beginner's Workshop (german)
Gradle - Beginner's Workshop (german)Gradle - Beginner's Workshop (german)
Gradle - Beginner's Workshop (german)Joachim Baumann
 
Test-driven Development mit TYPO3
Test-driven Development mit TYPO3Test-driven Development mit TYPO3
Test-driven Development mit TYPO3Oliver Klee
 
Funktionstests in SAP
Funktionstests in SAPFunktionstests in SAP
Funktionstests in SAPCadaxo GmbH
 
Die nächste Generation des Unit Testing
Die nächste Generation des Unit TestingDie nächste Generation des Unit Testing
Die nächste Generation des Unit TestingDaniel Lehner
 
Mögen die Tests mit dir sein
Mögen die Tests mit dir seinMögen die Tests mit dir sein
Mögen die Tests mit dir seincodepitbull
 
BASTA 2016 - Alternativen zu Visual-Studio-Testtools: Wann lohnt es sich auch...
BASTA 2016 - Alternativen zu Visual-Studio-Testtools: Wann lohnt es sich auch...BASTA 2016 - Alternativen zu Visual-Studio-Testtools: Wann lohnt es sich auch...
BASTA 2016 - Alternativen zu Visual-Studio-Testtools: Wann lohnt es sich auch...Marc Müller
 
PHPUnit - Eine kurze Einführung
PHPUnit - Eine kurze EinführungPHPUnit - Eine kurze Einführung
PHPUnit - Eine kurze Einführungfrankstaude
 
Softwarequalitätssicherung mit Continuous Integration Tools
 Softwarequalitätssicherung mit Continuous Integration Tools Softwarequalitätssicherung mit Continuous Integration Tools
Softwarequalitätssicherung mit Continuous Integration Toolsgedoplan
 
JSF Testing - Tools und Technics
JSF Testing - Tools und TechnicsJSF Testing - Tools und Technics
JSF Testing - Tools und Technicsadesso AG
 
Testing XAML-based Windows Store Apps mit VS 2013
Testing XAML-based Windows Store Apps mit VS 2013Testing XAML-based Windows Store Apps mit VS 2013
Testing XAML-based Windows Store Apps mit VS 2013Nico Orschel
 
Skripting prüfung, automatisierung und funktionserweiterung - Sebastian-Nic...
Skripting   prüfung, automatisierung und funktionserweiterung - Sebastian-Nic...Skripting   prüfung, automatisierung und funktionserweiterung - Sebastian-Nic...
Skripting prüfung, automatisierung und funktionserweiterung - Sebastian-Nic...MAX2014DACH
 
DWX 2017 - Alternativen zu Visual-Studio-Testtools: Wann lohnt es sich auch m...
DWX 2017 - Alternativen zu Visual-Studio-Testtools: Wann lohnt es sich auch m...DWX 2017 - Alternativen zu Visual-Studio-Testtools: Wann lohnt es sich auch m...
DWX 2017 - Alternativen zu Visual-Studio-Testtools: Wann lohnt es sich auch m...Marc Müller
 
Robustes Testen mit Selenium
Robustes Testen mit SeleniumRobustes Testen mit Selenium
Robustes Testen mit Seleniumx-celerate
 
Next Level Unit Testing
Next Level Unit TestingNext Level Unit Testing
Next Level Unit TestingDaniel Lehner
 

Ähnlich wie AdvancedTdd (20)

Best Practices für TDD in JavaScript
Best Practices für TDD in JavaScriptBest Practices für TDD in JavaScript
Best Practices für TDD in JavaScript
 
Unit testing mit Javascript
Unit testing mit JavascriptUnit testing mit Javascript
Unit testing mit Javascript
 
Einführung Vorgehensmodelle und Agile Software Entwicklung
Einführung Vorgehensmodelle und Agile Software EntwicklungEinführung Vorgehensmodelle und Agile Software Entwicklung
Einführung Vorgehensmodelle und Agile Software Entwicklung
 
Softwarequalitätssicherung mit Continuous Integration Tools
Softwarequalitätssicherung mit Continuous Integration ToolsSoftwarequalitätssicherung mit Continuous Integration Tools
Softwarequalitätssicherung mit Continuous Integration Tools
 
Wjax integrationsprojekte auf dem weg zur continuous delivery 2011 11-10
Wjax integrationsprojekte auf dem weg zur continuous delivery 2011 11-10Wjax integrationsprojekte auf dem weg zur continuous delivery 2011 11-10
Wjax integrationsprojekte auf dem weg zur continuous delivery 2011 11-10
 
Gradle - Beginner's Workshop (german)
Gradle - Beginner's Workshop (german)Gradle - Beginner's Workshop (german)
Gradle - Beginner's Workshop (german)
 
Test-driven Development mit TYPO3
Test-driven Development mit TYPO3Test-driven Development mit TYPO3
Test-driven Development mit TYPO3
 
Funktionstests in SAP
Funktionstests in SAPFunktionstests in SAP
Funktionstests in SAP
 
Die nächste Generation des Unit Testing
Die nächste Generation des Unit TestingDie nächste Generation des Unit Testing
Die nächste Generation des Unit Testing
 
Mögen die Tests mit dir sein
Mögen die Tests mit dir seinMögen die Tests mit dir sein
Mögen die Tests mit dir sein
 
BASTA 2016 - Alternativen zu Visual-Studio-Testtools: Wann lohnt es sich auch...
BASTA 2016 - Alternativen zu Visual-Studio-Testtools: Wann lohnt es sich auch...BASTA 2016 - Alternativen zu Visual-Studio-Testtools: Wann lohnt es sich auch...
BASTA 2016 - Alternativen zu Visual-Studio-Testtools: Wann lohnt es sich auch...
 
PHPUnit - Eine kurze Einführung
PHPUnit - Eine kurze EinführungPHPUnit - Eine kurze Einführung
PHPUnit - Eine kurze Einführung
 
Softwarequalitätssicherung mit Continuous Integration Tools
 Softwarequalitätssicherung mit Continuous Integration Tools Softwarequalitätssicherung mit Continuous Integration Tools
Softwarequalitätssicherung mit Continuous Integration Tools
 
A/B Testing mit Node.js
A/B Testing mit Node.jsA/B Testing mit Node.js
A/B Testing mit Node.js
 
JSF Testing - Tools und Technics
JSF Testing - Tools und TechnicsJSF Testing - Tools und Technics
JSF Testing - Tools und Technics
 
Testing XAML-based Windows Store Apps mit VS 2013
Testing XAML-based Windows Store Apps mit VS 2013Testing XAML-based Windows Store Apps mit VS 2013
Testing XAML-based Windows Store Apps mit VS 2013
 
Skripting prüfung, automatisierung und funktionserweiterung - Sebastian-Nic...
Skripting   prüfung, automatisierung und funktionserweiterung - Sebastian-Nic...Skripting   prüfung, automatisierung und funktionserweiterung - Sebastian-Nic...
Skripting prüfung, automatisierung und funktionserweiterung - Sebastian-Nic...
 
DWX 2017 - Alternativen zu Visual-Studio-Testtools: Wann lohnt es sich auch m...
DWX 2017 - Alternativen zu Visual-Studio-Testtools: Wann lohnt es sich auch m...DWX 2017 - Alternativen zu Visual-Studio-Testtools: Wann lohnt es sich auch m...
DWX 2017 - Alternativen zu Visual-Studio-Testtools: Wann lohnt es sich auch m...
 
Robustes Testen mit Selenium
Robustes Testen mit SeleniumRobustes Testen mit Selenium
Robustes Testen mit Selenium
 
Next Level Unit Testing
Next Level Unit TestingNext Level Unit Testing
Next Level Unit Testing
 

Mehr von jlink

Mein paralleles Leben als Java-Entwickler
Mein paralleles Leben als Java-EntwicklerMein paralleles Leben als Java-Entwickler
Mein paralleles Leben als Java-Entwicklerjlink
 
Java Script Ist Anders
Java Script Ist AndersJava Script Ist Anders
Java Script Ist Andersjlink
 
Agile08: Test Driven Ajax
Agile08: Test Driven AjaxAgile08: Test Driven Ajax
Agile08: Test Driven Ajaxjlink
 
Behaviour-Driven Development
Behaviour-Driven DevelopmentBehaviour-Driven Development
Behaviour-Driven Developmentjlink
 
Mehr Dynamik Durch Skriptsprachen
Mehr Dynamik Durch SkriptsprachenMehr Dynamik Durch Skriptsprachen
Mehr Dynamik Durch Skriptsprachenjlink
 
Mehr Dynamik Mit Groovy
Mehr Dynamik Mit GroovyMehr Dynamik Mit Groovy
Mehr Dynamik Mit Groovyjlink
 
Von Java Zu Groovy
Von Java Zu GroovyVon Java Zu Groovy
Von Java Zu Groovyjlink
 

Mehr von jlink (7)

Mein paralleles Leben als Java-Entwickler
Mein paralleles Leben als Java-EntwicklerMein paralleles Leben als Java-Entwickler
Mein paralleles Leben als Java-Entwickler
 
Java Script Ist Anders
Java Script Ist AndersJava Script Ist Anders
Java Script Ist Anders
 
Agile08: Test Driven Ajax
Agile08: Test Driven AjaxAgile08: Test Driven Ajax
Agile08: Test Driven Ajax
 
Behaviour-Driven Development
Behaviour-Driven DevelopmentBehaviour-Driven Development
Behaviour-Driven Development
 
Mehr Dynamik Durch Skriptsprachen
Mehr Dynamik Durch SkriptsprachenMehr Dynamik Durch Skriptsprachen
Mehr Dynamik Durch Skriptsprachen
 
Mehr Dynamik Mit Groovy
Mehr Dynamik Mit GroovyMehr Dynamik Mit Groovy
Mehr Dynamik Mit Groovy
 
Von Java Zu Groovy
Von Java Zu GroovyVon Java Zu Groovy
Von Java Zu Groovy
 

AdvancedTdd

  • 1. Fortgeschrittene Techniken der Testgetriebenen Entwicklung JAX Powerworkshop, 23.04.2007 Tammo Freese, Johannes Link
  • 2. Agenda • Testgetriebene Entwicklung im Überblick • Akzeptanztests mit FIT • Unit Tests mit JUnit/Mockobjekte mit EasyMock • Legacy Code und Code Coverage • Testen von GUIs und Web-Applikationen • Testen mit Skriptsprachen • Diskussion
  • 3. Motivation • Software hat Geschäftswert durch zwei Qualitäten • Funktionale Qualität (Funktionalität, Fehlerfreiheit) • Strukturelle Qualität (Design/Codestruktur für Weiterentwicklung) • Hinzufügen neuer Funktionalität gefährdet funktionale und strukturelle Qualität • Verbesserung der strukturellen Qualität gefährdet die funktionale Qualität
  • 4. Testgetriebene Entwicklung • Testgetriebene Programmierung: Motiviere jede Verhaltensänderung am Code durch einen automatisierten Test (ständige Absicherung der funktionalen Qualität) • Refactoring: Vereinfache das Code-Design soweit wie möglich (funktionale Qualität ist durch Tests abgesichert) • (Häufige Integration: Integriere den Code so häufig wie nötig)
  • 5. Entwickler schreiben Unit Tests • testen Komponenten des Systems in Isolation • geben uns konkretes Feedback • ermöglichen sichere Änderungen • sichern Erhalt der vorhandenen Funktionalität • müssen bei jeder Integration zu 100% laufen • können funktionale Tests auf Systemebene nicht ersetzen!
  • 6. Kunden spezifizieren Akzeptanztests • testen das System überwiegend als Ganzes • geben unseren Kunden Vertrauen in die gelieferte Software • klären die Anforderungen frühzeitig an konkreten Beispielen • machen den Projektfortschritt sichtbar • müssen vom Kunden erstellt und gepflegt werden können • Unsere Aufgabe ist es, den entsprechenden Rahmen für ihre Automatisierung zu schaen!
  • 7. Akzeptanztests mit FIT • FIT: Framework for Integrated Test • Zum Schreiben und Ausführen automatischer Akzeptanztests • Testdaten werden tabellarisch erstellt (in HTML, mit Excel oder im Wiki) • Anbindung ans System in Java • Portierung für aktuelle Sprachen verfügbar • http://fit.c2.com
  • 8. Drei Fixture-Klassen • ColumnFixture testet Ein-/Ausgabewertemengen. • ActionFixture spielt ein Benutzerszenario durch und ist deshalb gut für GUI-orientierte Tests geeignet. • RowFixture prüft eine Ergebnismenge von Objekten mit ihren Attributen.
  • 10. Column Fixture (2) import fit.ColumnFixture; public class AccountTransferFixture extends ColumnFixture { public String sourceAccount; public String targetAccount; public double amountTransferred; public boolean wasTransactionSuccessful() throws AccountException { return false; } }
  • 12. Action Fixture (2) import fit.ActionFixture; public class AccountAdministrationFixture extends ActionFixture { public void newAccount() {} public void customerName(String name) {} public String accountNumber() { return 0; } public void deposit(double money) throws AccountException { } public double balance() { return 0; } }
  • 13. Row Fixture (1) public class AccountListingItem { public String accountNumber; public double balance() { return 0; } public String customerName() { return dummy; } }
  • 14. Row Fixture (2) import fit.RowFixture; public class AccountListingFixture extends RowFixture { public Object[] query() throws Exception { List result = new ArrayList(); return result.toArray(); } public Class getTargetClass() { return AccountListingItem.class; } }
  • 15. Domänenspezifische Fixtures • wenn keine Fixture-Grundart so richtig passt • Erweiterungen von fit.Fixture über Hook- Methoden: • doTables(Parse tables) • doTable(Parse table) • doRows(Parse rows) • doRow(Parse row) • doCells(Parse cells) • doCell(Parse cell, int index)
  • 16. Übung 1: Akzeptanztestgetriebene Entwicklung • Bringen Sie die Testfälle in acceptance-tests/RichCalc.html schrittweise zum laufen! • (TaschenrechnerFixture.java ist eine ColumnFixture)
  • 17. Nachlese Übung 1 • Probleme bei akzeptanztestgetriebener Entwicklung • (Zu) große Schritte: Es dauert oft zu lange, einen Test auf grün zu bringen • Keine Möglichkeit, Design zu erzwingen • Keine Möglichkeit, Module isoliert ins Leben zu testen • Kombinatorische Explosion • Lösung: Unit Tests • Viele kleine Unit Tests schreiben • Jeden Akzeptanztest schrittweise erfüllen
  • 18. JUnit - Testframework für Java • Java-Framework zum Schreiben und Ausführen automatischer Unit Tests • Tests werden in Java codiert • Ist auch für zahlreiche andere Programmiersprachen erhältlich • http://junit.org
  • 19. Beispiel: Test import org.junit.Test; import static org.junit.Assert.*; public class EuroTest { @Test public void cents() { Euro two = new Euro(2.00); assertEquals(200, two.getCents()); } }
  • 20. Anatomie eines Testfallklasse • Testfallmethoden @Test public void ...() • Verwendung der statisch importierten Methoden assert...() und fail() • Fehlschlag von assert...() beendet den Testfall • Instanzvariablen für Testobjekte • @Before public void ...() zum Aufbau von Testobjekten und Testressourcen • @After public void ...() zur Ressourcenfreigabe
  • 21. Beispiel: Test Suite import org.junit.runner.RunWith; import org.junit.runners.Suite; import org.junit.runners.Suite.SuiteClasses; @RunWith(value = Suite.class) @SuiteClasses( { CalculatorTest.class }) public class AllTests { }
  • 24. Test/Code/Refactor – Schritte • grün-rot: Schreibe einen Test, der zunächst fehlschlagen sollte. Schreibe gerade soviel Code, dass der Test fehlschlägt. • rot-grün: Schreibe gerade soviel Code, dass alle Tests laufen. • grün-grün: Eliminiere Duplikation und andere üble Codegerüche.
  • 25. Programmierzug grün - rot • Programming by Intention: Der Test verwendet die zu testende Funktion, als wäre sie schon realisiert. • Die Klassenschnittstelle wird im Test aus der Perspektive eines Verwenders entworfen. • Jeder Test geht einen kleinen Schritt. • Den Test zunächst fehlschlagen zu sehen, testet den Test selbst.
  • 26. Programmierzug rot - grün • Nur soviel Code schreiben, wie die Tests erfordern. • Mehr wäre weder durch die Tests spezifiziert, noch abgesichert. • Erst weitere Tests beweisen, dass die Lösung eventuell noch zu einfach ist.
  • 27. Refactoringzug grün - grün • Eliminierung von Duplikation! • Verbesserungen am Design des Programms, ohne sein beobachtbares Verhalten zu ändern, • um die Verständlichkeit zu erhöhen • um Designschwächen zu beheben • um die Änderbarkeit zu erhalten.
  • 28. Strikte Unit Tests • Ein Unit Test soll eine Klasse oder ein Klassenteam in Isolation testen. • Probleme: • Programmeinheiten arbeiten nicht isoliert. • Aufbau der Testumgebung ist oft aufwändig. • Testen von Ausnahmesituationen • langsame Tests bei Überschreiten der Systemgrenzen
  • 29. Isoliertes Testen • Für die Dauer der Tests ersetzen wir Abhängigkeiten zu mitwirkenden Programmeinheiten durch die Einführung einfacher Attrappen.  • Vorteile: • Tests laufen schnell. • Auftretende Fehler sind leicht zu lokalisieren. • Notwendige Testkombinatorik ist kleiner als beim Testen mehrerer Objekte.
  • 31. Mock-Objekte • Ersetzen von der zu testenden Unit verwendeten Klassen oder Schnittstellen während des Tests • Vorgehen: • Verhalten und Erwartungen spezifizieren • Unit unter Verwendung des Mockobjekts testen • korrekte Verwendung verifizieren
  • 32. EasyMock – Dynamische Mock-Objekte • Erzeugung eines Mock-Objekts „on the fly“: • MyInterface mock = createMock(MyInterface.class); • Aufzeichnen des erwarteten Verhaltens: • expect(mock.myMethod(42))andReturn(Y); replay(mock); • Verifikation der Verwendung des Verhaltens: • verify(mock); • http://easymock.org/
  • 33. Systemgrenzen im Test • Dummies und Mocks: • Was wir zur Isolation innerhalb des Systems verwenden, funktioniert auch an Systemgrenzen. • Bei komplexen Systemgrenzen: • Fassade/Adapter zur zusätzlichen Indirektion einführen • Testen vom System zu Fassade/Adapter • Testen von Fassade/Adapter zur Systemgrenze • funktionale Tests testen das Zusammenspiel
  • 34. Übung 2: Isolierte Unit Tests • Bringen Sie die Testfälle in acceptance-tests/RichCalc.html schrittweise zum laufen! • Diesmal aber: • Schreiben Sie Unit Tests für die Akzeptanztests • Setzen Sie Mockobjekte ein, falls nötig • Startlinie: calculator.unittests.CalculatorTest
  • 35. Code Coverage • Wie gut sind unsere Tests? • Wie groß ist die Abdeckung des Codes durch unsere Tests? • http://www.cenqua.com/clover/ • http://works.dgic.co.jp/djunit/ • http://www.eclemma.org/ • Welche Code-Änderungen werden durch unsere Tests entdeckt? • http://jester.sourceforge.net/ • Metriken als Spiegel der Gewohnheit
  • 36. Testen von Legacy Code • Legacy Code ist Code ohne automatisierte Tests! • Michael Feathers: „Code without tests is bad code. It doesn't matter how well written it is [...] With tests, we can change the behavior of our code quickly and verifiably. Without them, we really don't know if our code is getting better or worse.“
  • 37. Legacy Code Dilemma • Um Software sicher zu ändern, benötigen wir automatisierte Tests. • Um automatisierte Tests zu schreiben, müssen wir die Software ändern. • Refactoring ohne Tests unumgänglich
  • 38. Testen von bestehendem Code • Änderung des bestehenden Systems • neue Features • Entfernen von Bugs • Designverbesserungen • Optimierungen • Vergrößerung der Testabdeckung • Testgetriebene Entwicklung • Charakterisierende Tests • Integrationstests
  • 39. Störende Abhängigkeiten • Eine Klasse lässt sich nicht instanzieren • Eine Methode lässt sich nicht ausführen • Das Testergebnis lässt sich nicht ermitteln
  • 40. Vorgehen 1. Identifiziere Änderungspunkte 2. Finde Testpunkte 3. Brich Abhängigkeiten 4. Schreibe automatisierte Tests 5. Mache Änderung 6. Räume auf (Refactoring)
  • 41. Werkzeugkasten • Automatisierte Refactorings • JUnit Test-Framework • Mock-Objekte als Attrappen • Framework for Integrated Test (FIT) • Aspektorientierte Programmierung
  • 42. Einschleusen von Mocks • als Parameter • über testbare Unterklasse • mittels Überlagerung im Klassenpfad • mit aspektorientierter Programmierung • in C/C++ auch über Linker und Präprozessor • Jedes Testproblem lässt sich über eine weitere Indirektion lösen
  • 43. Meine Klasse lehnt sich gegen den Test auf • Ursachen: • Klasse kann nicht instanziert werden • Hinderliche Konstruktor-Parameter • Konstruktor hat Seiteneekte • Techniken: • Extrahiere und überschreibe Methode • Extrahiere Interface • Parametrisiere Konstruktor
  • 44. Extrahiere und Überschreibe (1) public class A { public class A { public A() { public A() { B b = makeB(); B b = new B(); b.doStuff(); b.doStuff(); ... ... } } protected B makeB() { } return new B(); } }
  • 45. Extrahiere und Überschreibe (2) public class TestableA extends A { protected B makeB() { return new DummyB(); } } public class DummyB extends B { public void doStuff() { } }
  • 46. Extrahiere Interface public class A { public class A { public A() { public A() { IB b = makeB(); B b = makeB(); b.doStuff(); b.doStuff(); ... ... } } protected IB makeB() { protected B makeB() { return new B(); return new B(); } } } }
  • 47. Parametrisiere Konstruktor public class A { public class A { private IB b; public A() { public A(IB b) { IB b = makeB(); this.b = b; b.doStuff(); b.doStuff(); ... ... } } } public A() { this(new B()); } }
  • 48. Weitere Techniken • Abzweigende Methode • Abzweigende Klasse • Statisch gemachte Methoden • Primitivere Parametertypen • Führe statischen Setter ein • Führe delegierende Instanz ein • Ersetze Singleton durch direkte Abhängigkeit • Extrahiere Methoden • Extrahiere Methodenobjekt
  • 49. Verbesserungen über die Zeit • Viele der Techniken machen das Design zunächst einmal hässlicher • Durch die ersten installierten Tests sind kleine Verbesserungen möglich • Kleine Verbesserungen lassen weitere Refactoringkandidaten erkennen • Schrittweise zu evolutionärem Design
  • 50. Testen von GUIs und Web-Applikationen • Wichtigster Grundsatz: Keine Logik im View • Entwurfsmuster zur Trennung von Präsentation und Geschäftslogik: • Application Facade • Model View Presenter
  • 51. Application Facade interface BookSearchFacade BookSearchDialog searchTitles(searchExpression:String) : List Book Title Author
  • 52. Application Facade mit Observer interface Observer changeOccurred() implements interface BookSearchFacade BookSearchDialog searchTitles(searchExpression:String) : List registerObserver(observer: Observer) changeOccurred() Book Title Author
  • 53. Model View Presenter interface interface BookSearchView BookSearchPresenter displayList(books:List) search (searchExpression:String) implements implements BookSearchDialog BookSearcher displayList(books:List) search (searchExpression:String)
  • 54. Testen mit Skriptsprachen • Dynamisch typisierte Skriptsprachen können das Testen vereinfachen • Beispiel Groovy: • Alle Java-Features und Bibliotheken verfügbar • Typisierung ist optional • „Duck-Typing“ ist möglich • Einfache Syntax für Blocks und Iteratoren
  • 55. Groovy: Vereinfachte Syntax • Viele Elemente optional: • public, Typisierung, Parameterklammern, Semikolon class CalculatorTest extends GroovyTestCase { private calculator void setUp() { calculator = new Calculator() ... } void testDisplayThreeDigits() { checkDisplay '1', '5', '9' } def checkDisplay(String[] buttons) { ... }
  • 56. Groovy: Closures und Collections • Einfache Blocksyntax • Mächtige Collections • Iteratoren mittels Blöcken def printer = { line - println line } printer('Test') def buttons = [1, 2, 3, 4].reverse() def displayText = buttons.each { displayText += it } assert displayText == 4321
  • 57. Groovy: Dynamisch typisierte Objekte • „Anonyme“ Objekte on the fly def display = {assert it == displayText} as IDisplay def display = [display: {println it}, enableDecimalSeparatorKey: { ... }, disableDecimalSeparatorKey: { ... } ] as IDisplay
  • 58. Übung 3: Wie es euch gefällt • Variante 1: Schreiben Sie mit Hilfe von Jemmy eine Taschenrechner-Fixture, die direkt die Swing-GUI bedient • Variante 2: Erweitern Sie die Groovy-Testsuite im Package groovy.calculator.unittests • Variante 3: Erweitern Sie GUI und GUI-Tests: public interface IDisplay { void display(String toDisplay); void disableDecimalSeparatorKey(); void enableDecimalSeparatorKey(); }
  • 60. Referenzen • Michael Feathers: Working Eectively with Legacy Code. Prentice Hall, 2004. • Johannes Link: Softwaretests mit JUnit - Techniken der testgetriebenen Entwicklung. Dpunkt-Verlag, 2005. • Rick Mugridge, Ward Cunningham: Fit for Developing Software. Prentice Hall, 2005. • Frank Westphal: Testgetriebene Entwicklung mit JUnit FIT. Dpunkt-Verlag, 2005.