SlideShare ist ein Scribd-Unternehmen logo
2. Juni 2008
Johannes Link
Heidelberg
Mein eigener Chef
Mein eigener Chef
(Extremer) Softwareentwickler
Mein eigener Chef
(Extremer) Softwareentwickler
(Agiler) Coach
Mein eigener Chef
(Extremer) Softwareentwickler
(Agiler) Coach
Testgetrieben
johanneslink.net
Behaviour Driven
  Development
Behaviour Driven
  Development
Was. Warum. Wie.
TDD
Testgetriebene
 Entwicklung
Test / Code / Refactor



Tests Fail   Tests OK
Test / Code / Refactor

    1) Test hinzufügen

Tests Fail          Tests OK
Test / Code / Refactor

    1) Test hinzufügen

Tests Fail              Tests OK


     2) Test erfüllen
Test / Code / Refactor

    1) Test hinzufügen

                                   3) Code
Tests Fail              Tests OK   vereinfachen

     2) Test erfüllen
Warum TDD?
Regressionstests




          Warum TDD?
Regressionstests




        Weniger Bugs

          Warum TDD?
Regressionstests       Inkrementelles Vorgehen




        Weniger Bugs

          Warum TDD?
Regressionstests       Inkrementelles Vorgehen


    Designfokus

        Weniger Bugs

          Warum TDD?
Regressionstests       Inkrementelles Vorgehen

                   Entkopplung
    Designfokus

        Weniger Bugs

          Warum TDD?
Regressionstests       Inkrementelles Vorgehen

                   Entkopplung
    Designfokus
                         Schnittstellen
        Weniger Bugs

          Warum TDD?
Regressionstests       Inkrementelles Vorgehen

                   Entkopplung
    Designfokus
                         Schnittstellen
        Weniger Bugs

          Warum TDD?
  Ausführbare Spezifikation?
Regressionstests       Inkrementelles Vorgehen

                    Entkopplung
    Designfokus
                          Schnittstellen
        Weniger Bugs

          Warum TDD?
  Ausführbare Spezifikation?
                   Technische Dokumentation?
Typische TDD-Fragen
Wo fange ich an?




  Typische TDD-Fragen
Wo fange ich an?




  Typische TDD-Fragen


                   Wo höre ich auf?
Wo fange ich an?

     Wie nenne ich die
       Testklasse?


  Typische TDD-Fragen


                         Wo höre ich auf?
Wo fange ich an?

     Wie nenne ich die
       Testklasse?


  Typische TDD-Fragen
 Wie nenne ich die
  Testmethode?


                         Wo höre ich auf?
Wo fange ich an?

     Wie nenne ich die
       Testklasse?       Wie viele Assertions
                            pro Testfall?

  Typische TDD-Fragen
 Wie nenne ich die
  Testmethode?


                            Wo höre ich auf?
Wo fange ich an?            Welche Objekte
                         erzeuge ich im Setup?
     Wie nenne ich die
       Testklasse?       Wie viele Assertions
                            pro Testfall?

  Typische TDD-Fragen
 Wie nenne ich die
  Testmethode?


                             Wo höre ich auf?
Wo fange ich an?            Welche Objekte
                         erzeuge ich im Setup?
     Wie nenne ich die
       Testklasse?        Wie viele Assertions
                             pro Testfall?

  Typische TDD-Fragen
 Wie nenne ich die        Benötigt jede Klasse/
  Testmethode?            Methode eine eigene
                         Test-Klasse/-Methode?

                             Wo höre ich auf?
Wo fange ich an?              Welche Objekte
                           erzeuge ich im Setup?
     Wie nenne ich die
       Testklasse?          Wie viele Assertions
                               pro Testfall?

  Typische TDD-Fragen
 Wie nenne ich die          Benötigt jede Klasse/
  Testmethode?              Methode eine eigene
                           Test-Klasse/-Methode?
    Wie gruppiere und
   organisiere ich meine
                               Wo höre ich auf?
        Testfälle?
Schwammige Regeln
Heuristiken
Beispiel...
public class KontoTest {
	 @Test
	 public void neuesKonto() {
	 	 Konto konto = new Konto(quot;Johannesquot;);
	 	 assertEquals(quot;Johannesquot;, konto.getInhaber());
	 	 assertEquals(0, konto.getSaldo());
	 }
}
public class KontoTest...
	 private Konto konto;
	   @Before
	   public void init() {
	   	 konto = new Konto(quot;Johannesquot;);
	   }
	   @Test
	   public void neuesKonto() {
	   	 ...
	   }
	   @Test
	   public void einzahlung() {
	   	 konto.zahleEin(100);
	   	 assertEquals(100, konto.getSaldo());
	   	 konto.zahleEin(99);
	   	 assertEquals(199, konto.getSaldo());
	   }
public class KontoTest...
	 @Test
	 public void einzahlung() {
	 	 konto.zahleEin(100);
	 	 assertEquals(100, konto.getSaldo());
	 	 konto.zahleEin(99);
	 	 assertEquals(199, konto.getSaldo());
	 }
	   @Test(expected = IllegalArgumentException.class)
	   public void negativeEinzahlungNichtErlaubt() {
	   	 konto.zahleEin(-1);
	   }
public class KontoTest...
	 @Test
	 public void einzahlung() {
	 	 konto.zahleEin(100);
	 	 assertEquals(100, konto.getSaldo());
	 	 konto.zahleEin(99);
	 	 assertEquals(199, konto.getSaldo());
	 }
	   @Test(expected = IllegalArgumentException.class)
	   public void negativeEinzahlungNichtErlaubt() {
	   	 konto.zahleEin(100);
	   	 konto.zahleEin(-1);
	   }
public class KontoTest...
	 @Test
	 public void einzahlung() {
	 	 konto.zahleEin(100);
	 	 assertEquals(100, konto.getSaldo());
	 	 konto.zahleEin(99);
	 	 assertEquals(199, konto.getSaldo());
	 }
	   @Test(expected = IllegalArgumentException.class)
	   public void negativeEinzahlungNichtErlaubt() {
	   	 konto.zahleEin(100);
	   	 konto.zahleEin(-1);
	   }
public class NeuesKontoTest...
	 @Test public void inhaber()...
	 @Test public void anfangssaldo()...
	 @Test public void ersteEinzahlung()...

public class KontoMitPositivemSaldoTest...
	 private static final int ANFANGSSALDO = 100;
	   @Test public void einzahlung() {
	   	 konto.zahleEin(99);
	   	 assertEquals(99 + ANFANGSSALDO, konto.getSaldo());
	   }
	   @Test(expected = IllegalArgumentException.class)
	   public void negativeEinzahlungNichtErlaubt() {
	   	 konto.zahleEin(-1);
	   }
Gewünschtes
         Kontoverhalten
• Ein neues Konto
  • soll den Namen seines Inhabers mitteilen
      können
    • soll einen Saldo von 0 EUR haben
    • soll einen positiven Anfangssaldo eingezahlt
      bekommen können
•   Ein Konto mit positivem Saldo
    • soll den Saldo bei Einzahlungen
      entsprechenden vergrößern
    • soll bei negativen Einzahlungen eine
      IllegalArgumentException auslösen
public class EinNeuesKonto...
	 @Test public void sollInhaberLiefern()...
	 @Test public void sollAnfangssaldoNullHaben()...
	 @Test public void sollErsteEinzahlungErlauben()...

public class EinKontoMitPositivemSaldo...
	   @Test public void sollBeiPositiverEinzahlungSaldoErhöhen() {
	   	 konto.zahleEin(99);
	   	 assertThat(konto.getSaldo(), is(ANFANGSSALDO + 99));
	   	 //assertEquals(99 + ANFANGSSALDO, konto.getSaldo());
	 }
	 @Test public void sollBeiNegativerEinzahlung-
                       IllegalArgument-ExceptionWerfen()...
public class EinNeuesKonto...
	 @Test public void sollInhaberLiefern()...
	 @Test public void sollAnfangssaldoNullHaben()...
	 @Test public void sollErsteEinzahlungErlauben()...

public class EinKontoMitPositivemSaldo...
	   @Test public void sollBeiPositiverEinzahlungSaldoErhöhen() {
	   	 konto.zahleEin(99);
	   	 assertThat(konto.getSaldo(), is(ANFANGSSALDO + 99));
	   	 //assertEquals(99 + ANFANGSSALDO, konto.getSaldo());
	 }
	 @Test public void sollBeiNegativerEinzahlung-
                       IllegalArgument-ExceptionWerfen()...
Dan North
http://dannorth.net/introducing-bdd
BDD: Vom Test zum
    Verhalten
Die Sprache
beeinflusst unser
   Verhalten
Die Sprache des Testen
Die Sprache des Testen

Testfälle, Testen, Beweisen,
Sicherstellen, Programmeinheit,
Korrektheit, Vorbedingungen
Die Sprache des Testen

Testfälle, Testen, Beweisen,
Sicherstellen, Programmeinheit,
Korrektheit, Vorbedingungen
Wir versuchen mit Testfällen zu
beweisen, dass eine Programmeinheit
unter bestimmten Vorbedingungen
korrekt arbeitet
Die Sprache des Testen

Testfälle, Testen, Beweisen,
Sicherstellen, Programmeinheit,
Korrektheit, Vorbedingungen
Wir versuchen mit Testfällen zu
beweisen, dass eine Programmeinheit
unter bestimmten Vorbedingungen
korrekt arbeitet
Set Up - Stimulate - Assert
Die Sprache des BDD
Die Sprache des BDD

User Stories, Szenario,
Spezifikation,Verhalten, Kontext
Die Sprache des BDD

User Stories, Szenario,
Spezifikation,Verhalten, Kontext
Wir spezifizieren in Szenarien, wie sich
Dinge in einem bestimmten Kontext
verhalten sollen, um eine User Story zu
erfüllen
Die Sprache des BDD

User Stories, Szenario,
Spezifikation,Verhalten, Kontext
Wir spezifizieren in Szenarien, wie sich
Dinge in einem bestimmten Kontext
verhalten sollen, um eine User Story zu
erfüllen
Given - When - Then
Wie funktioniert
 meine Klasse?
Wie funktioniert
 meine Klasse?
Wie funktioniert
 meine Klasse?

 Was soll mein
Programm tun?
JBehave    Instinct
JDave



        Werkzeuge
GSpec     easyb

          RSpec      NSpec
Instinct
http://code.google.com/p/instinct/
@RunWith(InstinctRunner.class)
public class EinKontoMitPositivemSaldo {
	 private static final int ANFANGSSALDO = 42;
	 @Subject Konto konto;
	   @BeforeSpecification
	   void initialisiere() {
	   	   konto = new Konto(quot;Irgendwerquot;);
	   	   konto.zahleEin(ANFANGSSALDO);
	   }
	   @Specification(expectedException = IllegalArgumentException.class)
	   void sollBeiNegativerEinzahlungIllegalArgumentExceptionWerfen() {
	   	   konto.zahleEin(-1);
	   }
	   @Specification
	   void sollBeiPositiverEinzahlungenSaldoErhöhen() {
	   	   konto.zahleEin(1);
	   	   expect.that(konto.getSaldo()).isEqualTo(ANFANGSSALDO + 1);
	   	   konto.zahleEin(100);
	   	   expect.that(konto.getSaldo()).isEqualTo(ANFANGSSALDO + 101);
	   }
}
GSpec
http://groovy.codehaus.org/
Using+GSpec+with+Groovy
def ein = new GSpecBuilderRunner()
ein.context('Ein neues Konto') {
    def INHABER = quot;Johannesquot;	
    initially {
        ein.neuesKonto = new Konto(INHABER)
    }
    specify('soll den Inhaber als Property liefern') {
        ein.neuesKonto.inhaber.should_equal INHABER
    }
    specify('soll 0 EUR Anfangssaldo haben') {..}
    specify('soll positive Einzahlungen bekommen können') {..}
}
ein.context('Ein Konto mit positivem Saldo') {
    specify('soll bei positiver Einzahlungen den Saldo erhöhen') {..}
    specify('''soll bei negativer Einzahlungen
              IllegalArgumentException werfen''') {..}
}
def ein = new GSpecBuilderRunner()
ein.context('Ein neues Konto') {
    def INHABER = quot;Johannesquot;	
    initially {
        ein.neuesKonto = new Konto(INHABER)
    }
    specify('soll den Inhaber als Property liefern') {
        ein.neuesKonto.inhaber.should_equal INHABER
    }
    specify('soll 0 EUR Anfangssaldo haben') {..}
                         Ein neues Konto
                         soll den Inhaber als Property liefern
    specify('soll positive Einzahlungen bekommen können') {..}
}                        Ein neues Konto
                         soll 0 EUR Anfangssaldo haben
ein.context('Ein Konto mit positivem Saldo') {
                         Ein neues Konto
    specify('soll bei positiver Einzahlungen den Saldo erhöhen') {..}
                         soll positive Einzahlungen bekommen können
                         Ein Konto mit positivem Saldo
    specify('''soll bei negativer Einzahlungen
                         soll bei positiver Einzahlungen den Saldo erhöhen
               IllegalArgumentException werfen''') {..}
                         Ein Konto mit positivem Saldo
}                        soll bei negativer Einzahlungen
                            IllegalArgumentException werfen
easyb
http://www.easyb.org/
scenario quot;Konto mit ANFANGSSALDOquot;, {
	 def ANFANGSSALDO = 42
	 def BETRAG = 101
	 given quot;ein Konto mit SALDOquot;, {
	 	   konto = new Konto(quot;irgendwerquot;)
	 	   konto.zahleEin(ANFANGSSALDO)
	 }
	 when quot;ein BETRAG eingezahlt wirdquot;, {
	 	   konto.zahleEin(BETRAG)
	 }
	 then quot;der Saldo entspricht ANFANGSSALDO + BETRAGquot;, {
	 	   konto.getSaldo().shouldBe ANFANGSSALDO + BETRAG
	 }
}

scenario quot;Negative Einzahlungquot;, {
	 given quot;ein Kontoquot;, {...}
	 when quot;ein negativer Betrag eingezahlt wirdquot;, {
	 	   negativeEinzahlung = { konto.zahleEin(-1) }
	 }
	 then quot;eine IllegalArgumentException soll geworfen werdenquot;, {
	 	   ensureThrows(IllegalArgumentException) { negativeEinzahlung() }
	 }
}
scenario quot;Konto mit ANFANGSSALDOquot;, {
	 def ANFANGSSALDO = 42
	 def BETRAG = 101
	 given quot;ein Konto mit SALDOquot;, {einzelnes konto
                          Story:
	 	   konto = new Konto(quot;irgendwerquot;)
                            scenario Neues Konto
	 	   konto.zahleEin(ANFANGSSALDO)
                              given ein neues Konto
	 }
                              then der Inhaber ist als Property verfŸgbar
	 when quot;ein BETRAG eingezahltthen der {
                               wirdquot;, Anfangssaldo ist 0
	 	   konto.zahleEin(BETRAG)
	 }                         scenario Einfache Einzahlung
	 then quot;der Saldo entspricht given ein leeres BETRAGquot;, {
                              ANFANGSSALDO + Konto
	 	   konto.getSaldo().shouldBe ANFANGSSALDOeingezahlt wird
                              when ein BETRAG + BETRAG
	 }                           then der Saldo entspricht dem BETRAG
}
                            scenario Konto mit ANFANGSSALDO
scenario quot;Negative Einzahlungquot;, { ein Konto mit SALDO
                              given
	 given quot;ein Kontoquot;, {...}    when ein BETRAG eingezahlt wird
	 when quot;ein negativer Betrag then der Saldo entspricht ANFANGSSALDO + BETRAG
                              eingezahlt wirdquot;, {
	   	   negativeEinzahlung = { konto.zahleEin(-1) }
	   }                        scenario Negative Einzahlung
	                              given ein Konto
    then quot;eine IllegalArgumentException soll geworfen werdenquot;, {
        ensureThrows(IllegalArgumentException) { Betrag eingezahlt wird }
                               when ein negativer
	   	                                             negativeEinzahlung()
                               then eine IllegalArgumentException
	   }
                         	    	   	   soll geworfen werden
}
Veränderter Fokus
Veränderter Fokus
• Weg vom Wie - hin zum Was
  • User Stories -> Szenarios
  • Anfangszustand pro Szenario
  • Einzelne Zusicherungen
Veränderter Fokus
• Weg vom Wie - hin zum Was
  • User Stories -> Szenarios
  • Anfangszustand pro Szenario
  • Einzelne Zusicherungen
• Weg von der Unit - hin zum Verhalten
  • Geringere Kopplung zwischen Code und
      Spezifikation
  •   Refactoring vereinfacht
Veränderter Fokus
• Weg vom Wie - hin zum Was
  • User Stories -> Szenarios
  • Anfangszustand pro Szenario
  • Einzelne Zusicherungen
• Weg von der Unit - hin zum Verhalten
  • Geringere Kopplung zwischen Code und
      Spezifikation
    • Refactoring vereinfacht
•   Aber: Aussagekräftiges Reporting erfordert
    Investition in gute Texte
„Prozess“
Naives TDD
JDK
Technik
 JDK
Domänenmodell
   Technik
    JDK
Applikationsmodell
 Domänenmodell
     Technik
      JDK
Benutzerschnittstelle
 Applikationsmodell
  Domänenmodell
      Technik
        JDK
Anforderungen



Benutzerschnittstelle
 Applikationsmodell
  Domänenmodell
      Technik
        JDK
Von Außen nach
     Innen
Von Außen nach
        Innen
Vom Bekannten zum Unbekannten
JDK
Anforderungen




    JDK
Anforderungen



Benutzerschnittstelle




        JDK
Anforderungen



Benutzerschnittstelle
 Applikationsmodell




        JDK
Anforderungen



Benutzerschnittstelle
 Applikationsmodell
  Domänenmodell


        JDK
Anforderungen



Benutzerschnittstelle
 Applikationsmodell
  Domänenmodell
      Technik
        JDK
JDK
Anforderungen




    JDK
Anforderungen




Domänenmodell


    JDK
Anforderungen



Benutzerschnittstelle


  Domänenmodell


        JDK
Anforderungen



Benutzerschnittstelle
 Applikationsmodell
  Domänenmodell


        JDK
Anforderungen



Benutzerschnittstelle
 Applikationsmodell
  Domänenmodell
      Technik
        JDK
Domänenmodell
Anforderungen



Domänenmodell
Anforderungen



           Domänenmodell
Domänen-
 analyse
Domain Driven Design
     Eric Evans
Beispiel: Konten-GUI
Story: konten gui
Story: konten gui

scenario Leere Kontenliste anzeigen
   given eine Bank ohne Konten
   when die Konten-Applikation gestartet wird
   then dann ist das Konten-Fenster offen
   then ist die Liste der angezeigten Konten leer
Story: konten gui

scenario Leere Kontenliste anzeigen
   given eine Bank ohne Konten
   when die Konten-Applikation gestartet wird
   then dann ist das Konten-Fenster offen
   then ist die Liste der angezeigten Konten leer

scenario Gefüllte Kontenliste anzeigen
   given eine Bank mit drei Konten
   when die Konten-Applikation gestartet wird
   then werden im Konten-Fenster drei Konten
        mit Inhaber und Saldo angezeigt
Story: konten gui

scenario Leere Kontenliste anzeigen
   given eine Bank ohne Konten
   when die Konten-Applikation gestartet wird
   then dann ist das Konten-Fenster offen
   then ist die Liste der angezeigten Konten leer

scenario Gefüllte Kontenliste anzeigen
   given eine Bank mit drei Konten
   when die Konten-Applikation gestartet wird
   then werden im Konten-Fenster drei Konten
        mit Inhaber und Saldo angezeigt

scenario Löschen eines Kontos aus Kontenliste
   given ein offenes Konten-Fenster mit drei Konten
   when das erste Konto angewählt wird
   when der Löschen-Button gedrückt wird
   then verschwindet das Konto aus der Liste
   then wird an der Bank das Konto gelöscht
scenario quot;Leere Kontenliste anzeigenquot;, {
	 given quot;eine Bank ohne Kontenquot;
	 when quot;die Konten-Applikation gestartet wirdquot;
	 then quot;dann ist das Konten-Fenster offen quot;
	 and quot;ist die Liste der angezeigten Konten leerquot;
}
scenario quot;Leere Kontenliste anzeigenquot;, {
	 given quot;eine Bank ohne Kontenquot;, {
	 	 bank = new Bank()
	 }
	 when quot;die Konten-Applikation gestartet wirdquot;
	 then quot;dann ist das Konten-Fenster offen quot;
	 and quot;ist die Liste der angezeigten Konten leerquot;
}
import static org.mockito.Mockito.*
scenario quot;Leere Kontenliste anzeigenquot;, {
	 given quot;eine Bank ohne Kontenquot;, {
	 	 bank = new Bank()
            mock(IBank)
	 }
	 when quot;die Konten-Applikation gestartet wirdquot;
	 then quot;dann ist das Konten-Fenster offen quot;
	 and quot;ist die Liste der angezeigten Konten leerquot;
}
import static org.mockito.Mockito.*
scenario quot;Leere Kontenliste anzeigenquot;, {
	 given quot;eine Bank ohne Kontenquot;, {
	 	 bank = new Bank()
            mock(IBank)
	 }
	 when quot;die Konten-Applikation gestartet wirdquot;
	 then quot;dann ist das Konten-Fenster offen quot;
	 and quot;ist die Liste der angezeigten Konten leerquot;
}

public interface IBank {
}
import static org.mockito.Mockito.*
scenario quot;Leere Kontenliste anzeigenquot;, {
	 given quot;eine Bank ohne Kontenquot;, {
	 	 bank = mock(IBank)
	 	 stub(bank.getKonten()).toReturn([])
	 }
	 when quot;die Konten-Applikation gestartet wirdquot;
	 then quot;dann ist das Konten-Fenster offen quot;
	 and quot;ist die Liste der angezeigten Konten leerquot;
}
import static org.mockito.Mockito.*
scenario quot;Leere Kontenliste anzeigenquot;, {
	 given quot;eine Bank ohne Kontenquot;, {
	 	 bank = mock(IBank)
	 	 stub(bank.getKonten()).toReturn([])
	 }
	 when quot;die Konten-Applikation gestartet wirdquot;
	 then quot;dann ist das Konten-Fenster offen quot;
	 and quot;ist die Liste der angezeigten Konten leerquot;
}

public interface IBank {
	 List<Konto> getKonten();
}
import static org.mockito.Mockito.*
scenario quot;Leere Kontenliste anzeigenquot;, {
	 given quot;eine Bank ohne Kontenquot;, {
	 	 bank = mock(IBank)
	 	 stub(bank.getKonten()).toReturn([])
	 }
	 when quot;die Konten-Applikation gestartet wirdquot;, {
	 	 gui = new KontenApp(bank)
	 	 gui.setVisible(true)
	 }
	 then quot;dann ist das Konten-Fenster offen quot;
	 and quot;ist die Liste der angezeigten Konten leerquot;
}
import static org.mockito.Mockito.*
scenario quot;Leere Kontenliste anzeigenquot;, {
	 given quot;eine Bank ohne Kontenquot;, {
	 	 bank = mock(IBank)
	 	 stub(bank.getKonten()).toReturn([])
	 }
	 when quot;die Konten-Applikation gestartet wirdquot;, {
	 	 gui = new KontenApp(bank)
	 	 gui.setVisible(true)
	 }
	 then quot;dann ist das Konten-Fenster offen quot;
public class KontenApp extends JFrame {
	 and quot;ist die Liste der angezeigten Konten leerquot;
	 public KontenApp(IBank bank) {
}
	 }
}
import static org.mockito.Mockito.*
scenario quot;Leere Kontenliste anzeigenquot;, {
	 given quot;eine Bank ohne Kontenquot;, {
	 	 bank = mock(IBank)
	 	 stub(bank.getKonten()).toReturn([])
	 }
	 when quot;die Konten-Applikation gestartet wirdquot;, {
	 	 gui = new KontenApp(bank)
	 	 gui.setVisible(true)
	 }
	 then quot;dann ist das Konten-Fenster offen quot;, {
	 	 frame = new JFrameOperator(quot;Meine Kontenquot;)
	 }
	 and quot;ist die Liste der angezeigten Konten leerquot;
}
import static org.mockito.Mockito.*
scenario quot;Leere Kontenliste anzeigenquot;, {
	 given quot;eine Bank ohne Kontenquot;, {
	 	 bank = mock(IBank)
	 	 stub(bank.getKonten()).toReturn([])
	 }
	 when quot;die Konten-Applikation gestartet wirdquot;, {
	 	 gui = new KontenApp(bank)
	 	 gui.setVisible(true)
	 }
	 then quot;dann ist das Konten-Fenster offen quot;, {
	 	 frame = new JFrameOperator(quot;Meine Kontenquot;)
	 }
public quot;ist die Liste der angezeigten Konten leerquot;
	 and class KontenApp extends JFrame {
}
	 public KontenApp(IBank bank) {
	 	 super(quot;Meine Kontenquot;);
	 }
}
import static org.mockito.Mockito.*
scenario quot;Leere Kontenliste anzeigenquot;, {
	 given quot;eine Bank ohne Kontenquot;, {
	 	 bank = mock(IBank)
	 	 stub(bank.getKonten()).toReturn([])
	 }
	 when quot;die Konten-Applikation gestartet wirdquot;, {
	 	 gui = new KontenApp(bank)
	 	 gui.setVisible(true)
	 }
	 then quot;dann ist das Konten-Fenster offen quot;, {
	 	 frame = new JFrameOperator(quot;Meine Kontenquot;)
	 }
	 and quot;ist die Liste der angezeigten Konten leerquot;, {
	 	 table = new JTableOperator(frame);
	 	 table.model.rowCount.shouldBe 0	
	 }
	
}
public class KontenApp extends JFrame {
                         	   private JTable kontenTable;
                         	   private final IBank bank;
import static org.mockito.Mockito.*
                    	  public KontenApp(IBank  bank) {
                    	   	   super(quot;Meine Kontenquot;);
scenario quot;Leere Kontenliste anzeigenquot;, {
                    	   	   this.bank = bank;
	 given quot;eine Bank ohne 	Kontenquot;, {
                    	       createLayout();
	 	 bank = mock(IBank)}
                    	
	   	 stub(bank.getKonten()).toReturn([])
                      	   private void createLayout() {
	   }                 	   	   ...
                      	   	   createKontenTable();
	   when quot;die Konten-Applikation gestartet wirdquot;, {
                      	   	   fillKontenTable();
	   	 gui = new KontenApp(bank)
                      	   	   pack();
	   	 gui.setVisible(true)
                      	   }

	   }                 	   private void fillKontenTable() {

	   then quot;dann ist das	 Konten-Fenster offen quot;, {
                          	   ((KontenTableModel) kontenTable.getModel()).
                                  setKonten(bank.getKonten());
	   	 frame = new JFrameOperator(quot;Meine Kontenquot;)
                      	   }
	   }                 }
	   and quot;ist die Liste der angezeigten Konten leerquot;, {
	   	 table = new JTableOperator(frame);
	   	 table.model.rowCount.shouldBe 0	
	   }
	
}
public class KontenApp extends JFrame {
                         	   private JTable kontenTable;
                         	   private final IBank bank;
import static org.mockito.Mockito.*
                    	  public KontenApp(IBank  bank) {
                    	   	   super(quot;Meine Kontenquot;);
scenario quot;Leere Kontenliste anzeigenquot;, {
                    	   	   this.bank = bank;
	 given quot;eine Bank ohne 	Kontenquot;, {
                    	       createLayout();
	 	 bank = mock(IBank)}
                    	
	   	 stub(bank.getKonten()).toReturn([])
                      	   private void createLayout() {
	   }                 	   	   ...
                      	   	   createKontenTable();
	   when quot;die Konten-Applikation gestartet wirdquot;, {
                      	   	   fillKontenTable();
	   	 gui = new KontenApp(bank)
                      	   	   pack();
	   	 gui.setVisible(true)
                      	   }

	   }                 	   private void fillKontenTable() {

	   then quot;dann ist das	 Konten-Fenster offen quot;, {
                          	   ((KontenTableModel) kontenTable.getModel()).
                                  setKonten(bank.getKonten());
	   	 frame = new JFrameOperator(quot;Meine Kontenquot;)
                      	   }
	   }                 }
	   and quot;ist die Liste der angezeigten Konten leerquot;, {
	   	 table = new JTableOperator(frame);
	   	 table.model.rowCount.shouldBe 0	
	   }
	   gui.dispose()
}
Dummies und Mocks
 werden wichtiger
Dummies und Mocks
 werden wichtiger
import static org.mockito.Mockito.*
scenario quot;Leere Kontenliste anzeigenquot;, {
	 given quot;eine Bank ohne Kontenquot;, {
	 	 bank = mock(IBank)
	 	 stub(bank.getKonten()).toReturn([])
	 }
	 ...
}
scenario quot;Löschen eines Kontos aus Kontenlistequot;, {
	 given quot;ein offenes Konten-Fenster mit drei Kontenquot;, {...}
	 when quot;das erste Konto angewählt wirdquot;, {...}
	   and quot;der Löschen-Button gedrückt wirdquot;, {
	   	 deleteButton = new JButtonOperator(frame, quot;Lösche Kontoquot;)
	   	 deleteButton.push()
	   }
	 then quot;verschwindet das Konto aus der Listequot;, {
	 	 checkKontenliste(table.model, [[quot;in1quot;, 10], [quot;in2quot;, 20]])
	 }
	 and quot;wird an der Bank das Konto gelöschtquot;, {
	 	 ???
	 }
}
import static org.easymock.EasyMock.*
scenario quot;Löschen eines Kontos aus Kontenlistequot;, {
	 given quot;ein offenes Konten-Fenster mit drei Kontenquot;, {...}
	 when quot;das erste Konto angewählt wirdquot;, {...}
	   and quot;der Löschen-Button gedrückt wirdquot;, {
	   	 expect(bank.loescheKonto(dreiKonten[0]))
	   	 deleteButton = new JButtonOperator(frame, quot;Lösche Kontoquot;)
	   	 deleteButton.push()
	   }
	 then quot;verschwindet das Konto aus der Listequot;, {
	 	 checkKontenliste(table.model, [[quot;in1quot;, 10], [quot;in2quot;, 20]])
	 }
	 and quot;wird an der Bank das Konto gelöschtquot;, {
	 	 verify(bank)
	 }
}
import static org.mockito.Mockito.*
scenario quot;Löschen eines Kontos aus Kontenlistequot;, {
	 given quot;ein offenes Konten-Fenster mit drei Kontenquot;, {...}
	 when quot;das erste Konto angewählt wirdquot;, {...}
	   and quot;der Löschen-Button gedrückt wirdquot;, {
	   	 deleteButton = new JButtonOperator(frame, quot;Lösche Kontoquot;)
	   	 deleteButton.push()
	   }
	 then quot;verschwindet das Konto aus der Listequot;, {
	 	 checkKontenliste(table.model, [[quot;in1quot;, 10], [quot;in2quot;, 20]])
	 }
	 and quot;wird an der Bank das Konto gelöschtquot;, {
	 	 verify(bank).loescheKonto(dreiKonten[0])
	 }
}
Macht BDD
Akzeptanztests
 überflüssig?
Ziele von Akzeptanztests
Ziele von Akzeptanztests
• Funktionale Tests aus Kundensicht
Ziele von Akzeptanztests
• Funktionale Tests aus Kundensicht
• Sprechen die Sprache des Kunden
Ziele von Akzeptanztests
• Funktionale Tests aus Kundensicht
• Sprechen die Sprache des Kunden
• Konkrete Beispiele der Verwendung
Ziele von Akzeptanztests
• Funktionale Tests aus Kundensicht
• Sprechen die Sprache des Kunden
• Konkrete Beispiele der Verwendung
• Können vom Kunden geschrieben und
  geändert werden
Ziele von Akzeptanztests
• Funktionale Tests aus Kundensicht
• Sprechen die Sprache des Kunden
• Konkrete Beispiele der Verwendung
• Können vom Kunden geschrieben und
  geändert werden

• Testen (überwiegend) das System als
  Ganzes
Sind diese Ziele auch
mit BDD erreichbar?
scenario Gefüllte Kontenliste
         anzeigen
    given eine Bank mit drei Konten
    when die Konten-Applikation
         gestartet wird
    then werden im Konten-Fenster
         drei Konten mit Inhaber und
         Saldo angezeigt

scenario Löschen eines Kontos aus
         Kontenliste
    given ein offenes Konten-Fenster
          mit drei Konten
    when das erste Konto angewählt
         wird
    when der Löschen-Button gedrückt
         wird
    then verschwindet das Konto aus
         der Liste
    then wird an der Bank das Konto
         gelöscht
Funktionale Tests aus Kundensicht
Sprechen die Sprache des Kunden
Konkrete Beispiele der Verwendung
Können vom Kunden geschrieben und
geändert werden
Testen (überwiegend) das System als
Ganzes
 Funktionale Tests aus Kundensicht
  Sprechen die Sprache des Kunden
  Konkrete Beispiele der Verwendung
  Können vom Kunden geschrieben und
  geändert werden
  Testen (überwiegend) das System als
  Ganzes
 Funktionale Tests aus Kundensicht
 Sprechen die Sprache des Kunden
  Konkrete Beispiele der Verwendung
  Können vom Kunden geschrieben und
  geändert werden
  Testen (überwiegend) das System als
  Ganzes
 Funktionale Tests aus Kundensicht
 Sprechen die Sprache des Kunden
 Konkrete Beispiele der Verwendung
  Können vom Kunden geschrieben und
  geändert werden
  Testen (überwiegend) das System als
  Ganzes
 Funktionale Tests aus Kundensicht
   Sprechen die Sprache des Kunden
   Konkrete Beispiele der Verwendung
    Können vom Kunden geschrieben und
  geändert werden

    Testen (überwiegend) das System als
    Ganzes
 Funktionale Tests aus Kundensicht
   Sprechen die Sprache des Kunden
   Konkrete Beispiele der Verwendung
    Können vom Kunden geschrieben und
  geändert werden

   Testen (überwiegend) das System als
    Ganzes
BDD ist...
BDD ist...

• „Richtiges TDD“ leicht(er) gemacht
  • Veränderung der Sprache
  • Anpassung der Tools
BDD ist...

• „Richtiges TDD“ leicht(er) gemacht
  • Veränderung der Sprache
  • Anpassung der Tools
• Fokus auf Spezifikation und Verhalten
BDD ist...

• „Richtiges TDD“ leicht(er) gemacht
  • Veränderung der Sprache
  • Anpassung der Tools
• Fokus auf Spezifikation und Verhalten
• Vom Bekannten zum Unbekannten
  • Dummies und Mocks werden wichtiger
BDD ist...

• „Richtiges TDD“ leicht(er) gemacht
  • Veränderung der Sprache
  • Anpassung der Tools
• Fokus auf Spezifikation und Verhalten
• Vom Bekannten zum Unbekannten
  • Dummies und Mocks werden wichtiger
• Das Domänenmodell im Mittelpunkt
Web-Ressourcen
• http://jbehave.org/
• http://www.jdave.org/
• http://rspec.info/
• http://nspec.tigris.org/
• http://www.domaindrivendesign.org/
• http://mockito.org/
• http://jemmy.netbeans.org/
Fragen und
Anmerkungen?

Weitere ähnliche Inhalte

Andere mochten auch

Gruppenarbeit zum Lernerfolg
Gruppenarbeit zum LernerfolgGruppenarbeit zum Lernerfolg
Gruppenarbeit zum Lernerfolg
Berufsausbildung und Berufsvorbereitung
 
Gruppenarbeit zur Zukunft der Arbeit
Gruppenarbeit zur Zukunft der ArbeitGruppenarbeit zur Zukunft der Arbeit
Gruppenarbeit zur Zukunft der Arbeit
Berufsausbildung und Berufsvorbereitung
 
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
Wolfgang Luenenbuerger-Reidenbach
 
Kinder
KinderKinder
Kinderdokeos
 
Probleme und Konflikte in der Berufsausbildung erkennen und Gespräche vorbere...
Probleme und Konflikte in der Berufsausbildung erkennen und Gespräche vorbere...Probleme und Konflikte in der Berufsausbildung erkennen und Gespräche vorbere...
Probleme und Konflikte in der Berufsausbildung erkennen und Gespräche vorbere...
Berufsausbildung und Berufsvorbereitung
 
Netzpolitik GAL2011
Netzpolitik GAL2011Netzpolitik GAL2011
Sightseeing: Web 2.0 - Teaser
Sightseeing: Web 2.0 - TeaserSightseeing: Web 2.0 - Teaser
Sightseeing: Web 2.0 - Teaser
Anja C. Wagner
 
5
55
Wennmaneinmalfremdgeht
WennmaneinmalfremdgehtWennmaneinmalfremdgeht
Wennmaneinmalfremdgehtdokeos
 
AdvancedTdd
AdvancedTddAdvancedTdd
AdvancedTdd
jlink
 
Gruppenarbeit Lerntheorie Behaviorismus
Gruppenarbeit Lerntheorie BehaviorismusGruppenarbeit Lerntheorie Behaviorismus
Gruppenarbeit Lerntheorie Behaviorismus
Berufsausbildung und Berufsvorbereitung
 
Wer glaubt, mit Facebook Jugendliche zu erreichen, schreibt denen auch noch SMS
Wer glaubt, mit Facebook Jugendliche zu erreichen, schreibt denen auch noch SMSWer glaubt, mit Facebook Jugendliche zu erreichen, schreibt denen auch noch SMS
Wer glaubt, mit Facebook Jugendliche zu erreichen, schreibt denen auch noch SMS
Wolfgang Luenenbuerger-Reidenbach
 
Employee Blogging - to do or taboo
Employee Blogging - to do or tabooEmployee Blogging - to do or taboo
Employee Blogging - to do or taboo
Wolfgang Luenenbuerger-Reidenbach
 
Papagei
PapageiPapagei
Papageidokeos
 
Muss die Freiheit grenzenlos sein? Über Toleranz in der digitalen Welt
Muss die Freiheit grenzenlos sein? Über Toleranz in der digitalen WeltMuss die Freiheit grenzenlos sein? Über Toleranz in der digitalen Welt
Muss die Freiheit grenzenlos sein? Über Toleranz in der digitalen Welt
Wolfgang Luenenbuerger-Reidenbach
 
Wikis im Unterricht: Einsatzszenarien aus dem Fach Geschichte
Wikis im Unterricht: Einsatzszenarien aus dem Fach GeschichteWikis im Unterricht: Einsatzszenarien aus dem Fach Geschichte
Wikis im Unterricht: Einsatzszenarien aus dem Fach Geschichte
akoenig
 
Wuestenabenteuer
WuestenabenteuerWuestenabenteuer
Wuestenabenteuerdokeos
 

Andere mochten auch (20)

Empfehlungen
EmpfehlungenEmpfehlungen
Empfehlungen
 
Gruppenarbeit zum Lernerfolg
Gruppenarbeit zum LernerfolgGruppenarbeit zum Lernerfolg
Gruppenarbeit zum Lernerfolg
 
Gruppenarbeit demographie
Gruppenarbeit demographieGruppenarbeit demographie
Gruppenarbeit demographie
 
Gruppenarbeit zur Zukunft der Arbeit
Gruppenarbeit zur Zukunft der ArbeitGruppenarbeit zur Zukunft der Arbeit
Gruppenarbeit zur Zukunft der Arbeit
 
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
 
Kinder
KinderKinder
Kinder
 
Probleme und Konflikte in der Berufsausbildung erkennen und Gespräche vorbere...
Probleme und Konflikte in der Berufsausbildung erkennen und Gespräche vorbere...Probleme und Konflikte in der Berufsausbildung erkennen und Gespräche vorbere...
Probleme und Konflikte in der Berufsausbildung erkennen und Gespräche vorbere...
 
Netzpolitik GAL2011
Netzpolitik GAL2011Netzpolitik GAL2011
Netzpolitik GAL2011
 
Sightseeing: Web 2.0 - Teaser
Sightseeing: Web 2.0 - TeaserSightseeing: Web 2.0 - Teaser
Sightseeing: Web 2.0 - Teaser
 
5
55
5
 
Wennmaneinmalfremdgeht
WennmaneinmalfremdgehtWennmaneinmalfremdgeht
Wennmaneinmalfremdgeht
 
AdvancedTdd
AdvancedTddAdvancedTdd
AdvancedTdd
 
Gruppenarbeit Lerntheorie Behaviorismus
Gruppenarbeit Lerntheorie BehaviorismusGruppenarbeit Lerntheorie Behaviorismus
Gruppenarbeit Lerntheorie Behaviorismus
 
Wer glaubt, mit Facebook Jugendliche zu erreichen, schreibt denen auch noch SMS
Wer glaubt, mit Facebook Jugendliche zu erreichen, schreibt denen auch noch SMSWer glaubt, mit Facebook Jugendliche zu erreichen, schreibt denen auch noch SMS
Wer glaubt, mit Facebook Jugendliche zu erreichen, schreibt denen auch noch SMS
 
Employee Blogging - to do or taboo
Employee Blogging - to do or tabooEmployee Blogging - to do or taboo
Employee Blogging - to do or taboo
 
Papagei
PapageiPapagei
Papagei
 
Muss die Freiheit grenzenlos sein? Über Toleranz in der digitalen Welt
Muss die Freiheit grenzenlos sein? Über Toleranz in der digitalen WeltMuss die Freiheit grenzenlos sein? Über Toleranz in der digitalen Welt
Muss die Freiheit grenzenlos sein? Über Toleranz in der digitalen Welt
 
Wikis im Unterricht: Einsatzszenarien aus dem Fach Geschichte
Wikis im Unterricht: Einsatzszenarien aus dem Fach GeschichteWikis im Unterricht: Einsatzszenarien aus dem Fach Geschichte
Wikis im Unterricht: Einsatzszenarien aus dem Fach Geschichte
 
Wuestenabenteuer
WuestenabenteuerWuestenabenteuer
Wuestenabenteuer
 
Pech
PechPech
Pech
 

Ähnlich wie Behaviour-Driven Development

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
Daniel Lehner
 
Test-Alternativen
Test-AlternativenTest-Alternativen
Test-Alternativen
Sebastian Dietrich
 
Mastering architecture, design- and code-quality
Mastering architecture, design- and code-qualityMastering architecture, design- and code-quality
Mastering architecture, design- and code-quality
Sebastian Dietrich
 
Real Life TDD
Real Life TDDReal Life TDD
Real Life TDD
Daniel Rosowski
 
Testgetriebene Softwareentwicklung
Testgetriebene SoftwareentwicklungTestgetriebene Softwareentwicklung
Testgetriebene Softwareentwicklung
jlink
 
Kennst du ein Unternehmen, dass erfolgreich die QS outtasked hat?“
Kennst du einUnternehmen, dass erfolgreichdie QS outtasked hat?“Kennst du einUnternehmen, dass erfolgreichdie QS outtasked hat?“
Kennst du ein Unternehmen, dass erfolgreich die QS outtasked hat?“
hpaustria
 
Test-driven Development mit TYPO3
Test-driven Development mit TYPO3Test-driven Development mit TYPO3
Test-driven Development mit TYPO3Oliver Klee
 
Feige sein
Feige seinFeige sein
Feige sein
gedoplan
 
Ich will agil testen! was muss ich können iqnite 2014 - verison 2.0
Ich will agil testen! was muss ich können   iqnite 2014 - verison 2.0Ich will agil testen! was muss ich können   iqnite 2014 - verison 2.0
Ich will agil testen! was muss ich können iqnite 2014 - verison 2.0
Michael Fischlein
 
Clean Test Code (Clean Code Days)
Clean Test Code (Clean Code Days)Clean Test Code (Clean Code Days)
Clean Test Code (Clean Code Days)
David Völkel
 
Next Level Unit Testing
Next Level Unit TestingNext Level Unit Testing
Next Level Unit Testing
Daniel Lehner
 
Agiles Testen - Überblick
Agiles Testen - ÜberblickAgiles Testen - Überblick
Agiles Testen - Überblick
Claudia Haußmann 🦋
 
Unit testing mit Javascript
Unit testing mit JavascriptUnit testing mit Javascript
Unit testing mit Javascript
joergreichert
 
PHP mit Paul Bocuse
PHP mit Paul BocusePHP mit Paul Bocuse
PHP mit Paul Bocuse
Stephan Schmidt
 
UnitTests? Ja, aber richtig!
UnitTests? Ja, aber richtig!UnitTests? Ja, aber richtig!
UnitTests? Ja, aber richtig!
OPITZ CONSULTING Deutschland
 
Testen im EE-Umfeld – Seien Sie feige!
Testen im EE-Umfeld – Seien Sie feige!Testen im EE-Umfeld – Seien Sie feige!
Testen im EE-Umfeld – Seien Sie feige!
gedoplan
 
Good tests bad tests
Good tests bad testsGood tests bad tests
Good tests bad tests
Alexander Michehl
 
TDD mit ABAP Units
TDD mit ABAP UnitsTDD mit ABAP Units
TDD mit ABAP Units
Cadaxo GmbH
 
Agiles Testing
Agiles TestingAgiles Testing
Agiles Testing
NEOMO GmbH
 
DWX 2014 - Coded UI in der Praxis: Von Lokalisierung bis Nachhaltigkeit
DWX 2014 -  Coded UI in der Praxis: Von Lokalisierung bis NachhaltigkeitDWX 2014 -  Coded UI in der Praxis: Von Lokalisierung bis Nachhaltigkeit
DWX 2014 - Coded UI in der Praxis: Von Lokalisierung bis Nachhaltigkeit
Nico Orschel
 

Ähnlich wie Behaviour-Driven Development (20)

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
 
Test-Alternativen
Test-AlternativenTest-Alternativen
Test-Alternativen
 
Mastering architecture, design- and code-quality
Mastering architecture, design- and code-qualityMastering architecture, design- and code-quality
Mastering architecture, design- and code-quality
 
Real Life TDD
Real Life TDDReal Life TDD
Real Life TDD
 
Testgetriebene Softwareentwicklung
Testgetriebene SoftwareentwicklungTestgetriebene Softwareentwicklung
Testgetriebene Softwareentwicklung
 
Kennst du ein Unternehmen, dass erfolgreich die QS outtasked hat?“
Kennst du einUnternehmen, dass erfolgreichdie QS outtasked hat?“Kennst du einUnternehmen, dass erfolgreichdie QS outtasked hat?“
Kennst du ein Unternehmen, dass erfolgreich die QS outtasked hat?“
 
Test-driven Development mit TYPO3
Test-driven Development mit TYPO3Test-driven Development mit TYPO3
Test-driven Development mit TYPO3
 
Feige sein
Feige seinFeige sein
Feige sein
 
Ich will agil testen! was muss ich können iqnite 2014 - verison 2.0
Ich will agil testen! was muss ich können   iqnite 2014 - verison 2.0Ich will agil testen! was muss ich können   iqnite 2014 - verison 2.0
Ich will agil testen! was muss ich können iqnite 2014 - verison 2.0
 
Clean Test Code (Clean Code Days)
Clean Test Code (Clean Code Days)Clean Test Code (Clean Code Days)
Clean Test Code (Clean Code Days)
 
Next Level Unit Testing
Next Level Unit TestingNext Level Unit Testing
Next Level Unit Testing
 
Agiles Testen - Überblick
Agiles Testen - ÜberblickAgiles Testen - Überblick
Agiles Testen - Überblick
 
Unit testing mit Javascript
Unit testing mit JavascriptUnit testing mit Javascript
Unit testing mit Javascript
 
PHP mit Paul Bocuse
PHP mit Paul BocusePHP mit Paul Bocuse
PHP mit Paul Bocuse
 
UnitTests? Ja, aber richtig!
UnitTests? Ja, aber richtig!UnitTests? Ja, aber richtig!
UnitTests? Ja, aber richtig!
 
Testen im EE-Umfeld – Seien Sie feige!
Testen im EE-Umfeld – Seien Sie feige!Testen im EE-Umfeld – Seien Sie feige!
Testen im EE-Umfeld – Seien Sie feige!
 
Good tests bad tests
Good tests bad testsGood tests bad tests
Good tests bad tests
 
TDD mit ABAP Units
TDD mit ABAP UnitsTDD mit ABAP Units
TDD mit ABAP Units
 
Agiles Testing
Agiles TestingAgiles Testing
Agiles Testing
 
DWX 2014 - Coded UI in der Praxis: Von Lokalisierung bis Nachhaltigkeit
DWX 2014 -  Coded UI in der Praxis: Von Lokalisierung bis NachhaltigkeitDWX 2014 -  Coded UI in der Praxis: Von Lokalisierung bis Nachhaltigkeit
DWX 2014 - Coded UI in der Praxis: Von Lokalisierung bis Nachhaltigkeit
 

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-Entwickler
jlink
 
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 Ajax
jlink
 
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 Groovy
jlink
 
Von Java Zu Groovy
Von Java Zu GroovyVon Java Zu Groovy
Von Java Zu Groovy
jlink
 
Automated Web 2.0 Testing
Automated Web 2.0 TestingAutomated Web 2.0 Testing
Automated Web 2.0 Testing
jlink
 
XP Day Germany 2006 - Keynote
XP Day Germany 2006 - KeynoteXP Day Germany 2006 - Keynote
XP Day Germany 2006 - Keynote
jlink
 

Mehr von jlink (8)

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
 
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
 
Automated Web 2.0 Testing
Automated Web 2.0 TestingAutomated Web 2.0 Testing
Automated Web 2.0 Testing
 
XP Day Germany 2006 - Keynote
XP Day Germany 2006 - KeynoteXP Day Germany 2006 - Keynote
XP Day Germany 2006 - Keynote
 

Behaviour-Driven Development

  • 1.
  • 5.
  • 7. Mein eigener Chef (Extremer) Softwareentwickler
  • 8. Mein eigener Chef (Extremer) Softwareentwickler (Agiler) Coach
  • 9. Mein eigener Chef (Extremer) Softwareentwickler (Agiler) Coach Testgetrieben
  • 10.
  • 12. Behaviour Driven Development
  • 13. Behaviour Driven Development Was. Warum. Wie.
  • 14. TDD
  • 16. Test / Code / Refactor Tests Fail Tests OK
  • 17. Test / Code / Refactor 1) Test hinzufügen Tests Fail Tests OK
  • 18. Test / Code / Refactor 1) Test hinzufügen Tests Fail Tests OK 2) Test erfüllen
  • 19. Test / Code / Refactor 1) Test hinzufügen 3) Code Tests Fail Tests OK vereinfachen 2) Test erfüllen
  • 21. Regressionstests Warum TDD?
  • 22. Regressionstests Weniger Bugs Warum TDD?
  • 23. Regressionstests Inkrementelles Vorgehen Weniger Bugs Warum TDD?
  • 24. Regressionstests Inkrementelles Vorgehen Designfokus Weniger Bugs Warum TDD?
  • 25. Regressionstests Inkrementelles Vorgehen Entkopplung Designfokus Weniger Bugs Warum TDD?
  • 26. Regressionstests Inkrementelles Vorgehen Entkopplung Designfokus Schnittstellen Weniger Bugs Warum TDD?
  • 27. Regressionstests Inkrementelles Vorgehen Entkopplung Designfokus Schnittstellen Weniger Bugs Warum TDD? Ausführbare Spezifikation?
  • 28. Regressionstests Inkrementelles Vorgehen Entkopplung Designfokus Schnittstellen Weniger Bugs Warum TDD? Ausführbare Spezifikation? Technische Dokumentation?
  • 30. Wo fange ich an? Typische TDD-Fragen
  • 31. Wo fange ich an? Typische TDD-Fragen Wo höre ich auf?
  • 32. Wo fange ich an? Wie nenne ich die Testklasse? Typische TDD-Fragen Wo höre ich auf?
  • 33. Wo fange ich an? Wie nenne ich die Testklasse? Typische TDD-Fragen Wie nenne ich die Testmethode? Wo höre ich auf?
  • 34. Wo fange ich an? Wie nenne ich die Testklasse? Wie viele Assertions pro Testfall? Typische TDD-Fragen Wie nenne ich die Testmethode? Wo höre ich auf?
  • 35. Wo fange ich an? Welche Objekte erzeuge ich im Setup? Wie nenne ich die Testklasse? Wie viele Assertions pro Testfall? Typische TDD-Fragen Wie nenne ich die Testmethode? Wo höre ich auf?
  • 36. Wo fange ich an? Welche Objekte erzeuge ich im Setup? Wie nenne ich die Testklasse? Wie viele Assertions pro Testfall? Typische TDD-Fragen Wie nenne ich die Benötigt jede Klasse/ Testmethode? Methode eine eigene Test-Klasse/-Methode? Wo höre ich auf?
  • 37. Wo fange ich an? Welche Objekte erzeuge ich im Setup? Wie nenne ich die Testklasse? Wie viele Assertions pro Testfall? Typische TDD-Fragen Wie nenne ich die Benötigt jede Klasse/ Testmethode? Methode eine eigene Test-Klasse/-Methode? Wie gruppiere und organisiere ich meine Wo höre ich auf? Testfälle?
  • 41. public class KontoTest { @Test public void neuesKonto() { Konto konto = new Konto(quot;Johannesquot;); assertEquals(quot;Johannesquot;, konto.getInhaber()); assertEquals(0, konto.getSaldo()); } }
  • 42. public class KontoTest... private Konto konto; @Before public void init() { konto = new Konto(quot;Johannesquot;); } @Test public void neuesKonto() { ... } @Test public void einzahlung() { konto.zahleEin(100); assertEquals(100, konto.getSaldo()); konto.zahleEin(99); assertEquals(199, konto.getSaldo()); }
  • 43. public class KontoTest... @Test public void einzahlung() { konto.zahleEin(100); assertEquals(100, konto.getSaldo()); konto.zahleEin(99); assertEquals(199, konto.getSaldo()); } @Test(expected = IllegalArgumentException.class) public void negativeEinzahlungNichtErlaubt() { konto.zahleEin(-1); }
  • 44. public class KontoTest... @Test public void einzahlung() { konto.zahleEin(100); assertEquals(100, konto.getSaldo()); konto.zahleEin(99); assertEquals(199, konto.getSaldo()); } @Test(expected = IllegalArgumentException.class) public void negativeEinzahlungNichtErlaubt() { konto.zahleEin(100); konto.zahleEin(-1); }
  • 45. public class KontoTest... @Test public void einzahlung() { konto.zahleEin(100); assertEquals(100, konto.getSaldo()); konto.zahleEin(99); assertEquals(199, konto.getSaldo()); } @Test(expected = IllegalArgumentException.class) public void negativeEinzahlungNichtErlaubt() { konto.zahleEin(100); konto.zahleEin(-1); }
  • 46. public class NeuesKontoTest... @Test public void inhaber()... @Test public void anfangssaldo()... @Test public void ersteEinzahlung()... public class KontoMitPositivemSaldoTest... private static final int ANFANGSSALDO = 100; @Test public void einzahlung() { konto.zahleEin(99); assertEquals(99 + ANFANGSSALDO, konto.getSaldo()); } @Test(expected = IllegalArgumentException.class) public void negativeEinzahlungNichtErlaubt() { konto.zahleEin(-1); }
  • 47. Gewünschtes Kontoverhalten • Ein neues Konto • soll den Namen seines Inhabers mitteilen können • soll einen Saldo von 0 EUR haben • soll einen positiven Anfangssaldo eingezahlt bekommen können • Ein Konto mit positivem Saldo • soll den Saldo bei Einzahlungen entsprechenden vergrößern • soll bei negativen Einzahlungen eine IllegalArgumentException auslösen
  • 48. public class EinNeuesKonto... @Test public void sollInhaberLiefern()... @Test public void sollAnfangssaldoNullHaben()... @Test public void sollErsteEinzahlungErlauben()... public class EinKontoMitPositivemSaldo... @Test public void sollBeiPositiverEinzahlungSaldoErhöhen() { konto.zahleEin(99); assertThat(konto.getSaldo(), is(ANFANGSSALDO + 99)); //assertEquals(99 + ANFANGSSALDO, konto.getSaldo()); } @Test public void sollBeiNegativerEinzahlung- IllegalArgument-ExceptionWerfen()...
  • 49. public class EinNeuesKonto... @Test public void sollInhaberLiefern()... @Test public void sollAnfangssaldoNullHaben()... @Test public void sollErsteEinzahlungErlauben()... public class EinKontoMitPositivemSaldo... @Test public void sollBeiPositiverEinzahlungSaldoErhöhen() { konto.zahleEin(99); assertThat(konto.getSaldo(), is(ANFANGSSALDO + 99)); //assertEquals(99 + ANFANGSSALDO, konto.getSaldo()); } @Test public void sollBeiNegativerEinzahlung- IllegalArgument-ExceptionWerfen()...
  • 52. BDD: Vom Test zum Verhalten
  • 55. Die Sprache des Testen Testfälle, Testen, Beweisen, Sicherstellen, Programmeinheit, Korrektheit, Vorbedingungen
  • 56. Die Sprache des Testen Testfälle, Testen, Beweisen, Sicherstellen, Programmeinheit, Korrektheit, Vorbedingungen Wir versuchen mit Testfällen zu beweisen, dass eine Programmeinheit unter bestimmten Vorbedingungen korrekt arbeitet
  • 57. Die Sprache des Testen Testfälle, Testen, Beweisen, Sicherstellen, Programmeinheit, Korrektheit, Vorbedingungen Wir versuchen mit Testfällen zu beweisen, dass eine Programmeinheit unter bestimmten Vorbedingungen korrekt arbeitet Set Up - Stimulate - Assert
  • 59. Die Sprache des BDD User Stories, Szenario, Spezifikation,Verhalten, Kontext
  • 60. Die Sprache des BDD User Stories, Szenario, Spezifikation,Verhalten, Kontext Wir spezifizieren in Szenarien, wie sich Dinge in einem bestimmten Kontext verhalten sollen, um eine User Story zu erfüllen
  • 61. Die Sprache des BDD User Stories, Szenario, Spezifikation,Verhalten, Kontext Wir spezifizieren in Szenarien, wie sich Dinge in einem bestimmten Kontext verhalten sollen, um eine User Story zu erfüllen Given - When - Then
  • 64. Wie funktioniert meine Klasse? Was soll mein Programm tun?
  • 65. JBehave Instinct JDave Werkzeuge GSpec easyb RSpec NSpec
  • 67. @RunWith(InstinctRunner.class) public class EinKontoMitPositivemSaldo { private static final int ANFANGSSALDO = 42; @Subject Konto konto; @BeforeSpecification void initialisiere() { konto = new Konto(quot;Irgendwerquot;); konto.zahleEin(ANFANGSSALDO); } @Specification(expectedException = IllegalArgumentException.class) void sollBeiNegativerEinzahlungIllegalArgumentExceptionWerfen() { konto.zahleEin(-1); } @Specification void sollBeiPositiverEinzahlungenSaldoErhöhen() { konto.zahleEin(1); expect.that(konto.getSaldo()).isEqualTo(ANFANGSSALDO + 1); konto.zahleEin(100); expect.that(konto.getSaldo()).isEqualTo(ANFANGSSALDO + 101); } }
  • 69. def ein = new GSpecBuilderRunner() ein.context('Ein neues Konto') { def INHABER = quot;Johannesquot; initially { ein.neuesKonto = new Konto(INHABER) } specify('soll den Inhaber als Property liefern') { ein.neuesKonto.inhaber.should_equal INHABER } specify('soll 0 EUR Anfangssaldo haben') {..} specify('soll positive Einzahlungen bekommen können') {..} } ein.context('Ein Konto mit positivem Saldo') { specify('soll bei positiver Einzahlungen den Saldo erhöhen') {..} specify('''soll bei negativer Einzahlungen IllegalArgumentException werfen''') {..} }
  • 70. def ein = new GSpecBuilderRunner() ein.context('Ein neues Konto') { def INHABER = quot;Johannesquot; initially { ein.neuesKonto = new Konto(INHABER) } specify('soll den Inhaber als Property liefern') { ein.neuesKonto.inhaber.should_equal INHABER } specify('soll 0 EUR Anfangssaldo haben') {..} Ein neues Konto soll den Inhaber als Property liefern specify('soll positive Einzahlungen bekommen können') {..} } Ein neues Konto soll 0 EUR Anfangssaldo haben ein.context('Ein Konto mit positivem Saldo') { Ein neues Konto specify('soll bei positiver Einzahlungen den Saldo erhöhen') {..} soll positive Einzahlungen bekommen können Ein Konto mit positivem Saldo specify('''soll bei negativer Einzahlungen soll bei positiver Einzahlungen den Saldo erhöhen IllegalArgumentException werfen''') {..} Ein Konto mit positivem Saldo } soll bei negativer Einzahlungen IllegalArgumentException werfen
  • 72. scenario quot;Konto mit ANFANGSSALDOquot;, { def ANFANGSSALDO = 42 def BETRAG = 101 given quot;ein Konto mit SALDOquot;, { konto = new Konto(quot;irgendwerquot;) konto.zahleEin(ANFANGSSALDO) } when quot;ein BETRAG eingezahlt wirdquot;, { konto.zahleEin(BETRAG) } then quot;der Saldo entspricht ANFANGSSALDO + BETRAGquot;, { konto.getSaldo().shouldBe ANFANGSSALDO + BETRAG } } scenario quot;Negative Einzahlungquot;, { given quot;ein Kontoquot;, {...} when quot;ein negativer Betrag eingezahlt wirdquot;, { negativeEinzahlung = { konto.zahleEin(-1) } } then quot;eine IllegalArgumentException soll geworfen werdenquot;, { ensureThrows(IllegalArgumentException) { negativeEinzahlung() } } }
  • 73. scenario quot;Konto mit ANFANGSSALDOquot;, { def ANFANGSSALDO = 42 def BETRAG = 101 given quot;ein Konto mit SALDOquot;, {einzelnes konto Story: konto = new Konto(quot;irgendwerquot;) scenario Neues Konto konto.zahleEin(ANFANGSSALDO) given ein neues Konto } then der Inhaber ist als Property verfŸgbar when quot;ein BETRAG eingezahltthen der { wirdquot;, Anfangssaldo ist 0 konto.zahleEin(BETRAG) } scenario Einfache Einzahlung then quot;der Saldo entspricht given ein leeres BETRAGquot;, { ANFANGSSALDO + Konto konto.getSaldo().shouldBe ANFANGSSALDOeingezahlt wird when ein BETRAG + BETRAG } then der Saldo entspricht dem BETRAG } scenario Konto mit ANFANGSSALDO scenario quot;Negative Einzahlungquot;, { ein Konto mit SALDO given given quot;ein Kontoquot;, {...} when ein BETRAG eingezahlt wird when quot;ein negativer Betrag then der Saldo entspricht ANFANGSSALDO + BETRAG eingezahlt wirdquot;, { negativeEinzahlung = { konto.zahleEin(-1) } } scenario Negative Einzahlung given ein Konto then quot;eine IllegalArgumentException soll geworfen werdenquot;, { ensureThrows(IllegalArgumentException) { Betrag eingezahlt wird } when ein negativer negativeEinzahlung() then eine IllegalArgumentException } soll geworfen werden }
  • 75. Veränderter Fokus • Weg vom Wie - hin zum Was • User Stories -> Szenarios • Anfangszustand pro Szenario • Einzelne Zusicherungen
  • 76. Veränderter Fokus • Weg vom Wie - hin zum Was • User Stories -> Szenarios • Anfangszustand pro Szenario • Einzelne Zusicherungen • Weg von der Unit - hin zum Verhalten • Geringere Kopplung zwischen Code und Spezifikation • Refactoring vereinfacht
  • 77. Veränderter Fokus • Weg vom Wie - hin zum Was • User Stories -> Szenarios • Anfangszustand pro Szenario • Einzelne Zusicherungen • Weg von der Unit - hin zum Verhalten • Geringere Kopplung zwischen Code und Spezifikation • Refactoring vereinfacht • Aber: Aussagekräftiges Reporting erfordert Investition in gute Texte
  • 80. JDK
  • 82. Domänenmodell Technik JDK
  • 84. Benutzerschnittstelle Applikationsmodell Domänenmodell Technik JDK
  • 87. Von Außen nach Innen Vom Bekannten zum Unbekannten
  • 88. JDK
  • 94. JDK
  • 102. Anforderungen Domänenmodell Domänen- analyse
  • 103. Domain Driven Design Eric Evans
  • 106. Story: konten gui scenario Leere Kontenliste anzeigen given eine Bank ohne Konten when die Konten-Applikation gestartet wird then dann ist das Konten-Fenster offen then ist die Liste der angezeigten Konten leer
  • 107. Story: konten gui scenario Leere Kontenliste anzeigen given eine Bank ohne Konten when die Konten-Applikation gestartet wird then dann ist das Konten-Fenster offen then ist die Liste der angezeigten Konten leer scenario Gefüllte Kontenliste anzeigen given eine Bank mit drei Konten when die Konten-Applikation gestartet wird then werden im Konten-Fenster drei Konten mit Inhaber und Saldo angezeigt
  • 108. Story: konten gui scenario Leere Kontenliste anzeigen given eine Bank ohne Konten when die Konten-Applikation gestartet wird then dann ist das Konten-Fenster offen then ist die Liste der angezeigten Konten leer scenario Gefüllte Kontenliste anzeigen given eine Bank mit drei Konten when die Konten-Applikation gestartet wird then werden im Konten-Fenster drei Konten mit Inhaber und Saldo angezeigt scenario Löschen eines Kontos aus Kontenliste given ein offenes Konten-Fenster mit drei Konten when das erste Konto angewählt wird when der Löschen-Button gedrückt wird then verschwindet das Konto aus der Liste then wird an der Bank das Konto gelöscht
  • 109. scenario quot;Leere Kontenliste anzeigenquot;, { given quot;eine Bank ohne Kontenquot; when quot;die Konten-Applikation gestartet wirdquot; then quot;dann ist das Konten-Fenster offen quot; and quot;ist die Liste der angezeigten Konten leerquot; }
  • 110. scenario quot;Leere Kontenliste anzeigenquot;, { given quot;eine Bank ohne Kontenquot;, { bank = new Bank() } when quot;die Konten-Applikation gestartet wirdquot; then quot;dann ist das Konten-Fenster offen quot; and quot;ist die Liste der angezeigten Konten leerquot; }
  • 111. import static org.mockito.Mockito.* scenario quot;Leere Kontenliste anzeigenquot;, { given quot;eine Bank ohne Kontenquot;, { bank = new Bank() mock(IBank) } when quot;die Konten-Applikation gestartet wirdquot; then quot;dann ist das Konten-Fenster offen quot; and quot;ist die Liste der angezeigten Konten leerquot; }
  • 112. import static org.mockito.Mockito.* scenario quot;Leere Kontenliste anzeigenquot;, { given quot;eine Bank ohne Kontenquot;, { bank = new Bank() mock(IBank) } when quot;die Konten-Applikation gestartet wirdquot; then quot;dann ist das Konten-Fenster offen quot; and quot;ist die Liste der angezeigten Konten leerquot; } public interface IBank { }
  • 113. import static org.mockito.Mockito.* scenario quot;Leere Kontenliste anzeigenquot;, { given quot;eine Bank ohne Kontenquot;, { bank = mock(IBank) stub(bank.getKonten()).toReturn([]) } when quot;die Konten-Applikation gestartet wirdquot; then quot;dann ist das Konten-Fenster offen quot; and quot;ist die Liste der angezeigten Konten leerquot; }
  • 114. import static org.mockito.Mockito.* scenario quot;Leere Kontenliste anzeigenquot;, { given quot;eine Bank ohne Kontenquot;, { bank = mock(IBank) stub(bank.getKonten()).toReturn([]) } when quot;die Konten-Applikation gestartet wirdquot; then quot;dann ist das Konten-Fenster offen quot; and quot;ist die Liste der angezeigten Konten leerquot; } public interface IBank { List<Konto> getKonten(); }
  • 115. import static org.mockito.Mockito.* scenario quot;Leere Kontenliste anzeigenquot;, { given quot;eine Bank ohne Kontenquot;, { bank = mock(IBank) stub(bank.getKonten()).toReturn([]) } when quot;die Konten-Applikation gestartet wirdquot;, { gui = new KontenApp(bank) gui.setVisible(true) } then quot;dann ist das Konten-Fenster offen quot; and quot;ist die Liste der angezeigten Konten leerquot; }
  • 116. import static org.mockito.Mockito.* scenario quot;Leere Kontenliste anzeigenquot;, { given quot;eine Bank ohne Kontenquot;, { bank = mock(IBank) stub(bank.getKonten()).toReturn([]) } when quot;die Konten-Applikation gestartet wirdquot;, { gui = new KontenApp(bank) gui.setVisible(true) } then quot;dann ist das Konten-Fenster offen quot; public class KontenApp extends JFrame { and quot;ist die Liste der angezeigten Konten leerquot; public KontenApp(IBank bank) { } } }
  • 117. import static org.mockito.Mockito.* scenario quot;Leere Kontenliste anzeigenquot;, { given quot;eine Bank ohne Kontenquot;, { bank = mock(IBank) stub(bank.getKonten()).toReturn([]) } when quot;die Konten-Applikation gestartet wirdquot;, { gui = new KontenApp(bank) gui.setVisible(true) } then quot;dann ist das Konten-Fenster offen quot;, { frame = new JFrameOperator(quot;Meine Kontenquot;) } and quot;ist die Liste der angezeigten Konten leerquot; }
  • 118. import static org.mockito.Mockito.* scenario quot;Leere Kontenliste anzeigenquot;, { given quot;eine Bank ohne Kontenquot;, { bank = mock(IBank) stub(bank.getKonten()).toReturn([]) } when quot;die Konten-Applikation gestartet wirdquot;, { gui = new KontenApp(bank) gui.setVisible(true) } then quot;dann ist das Konten-Fenster offen quot;, { frame = new JFrameOperator(quot;Meine Kontenquot;) } public quot;ist die Liste der angezeigten Konten leerquot; and class KontenApp extends JFrame { } public KontenApp(IBank bank) { super(quot;Meine Kontenquot;); } }
  • 119. import static org.mockito.Mockito.* scenario quot;Leere Kontenliste anzeigenquot;, { given quot;eine Bank ohne Kontenquot;, { bank = mock(IBank) stub(bank.getKonten()).toReturn([]) } when quot;die Konten-Applikation gestartet wirdquot;, { gui = new KontenApp(bank) gui.setVisible(true) } then quot;dann ist das Konten-Fenster offen quot;, { frame = new JFrameOperator(quot;Meine Kontenquot;) } and quot;ist die Liste der angezeigten Konten leerquot;, { table = new JTableOperator(frame); table.model.rowCount.shouldBe 0 } }
  • 120. public class KontenApp extends JFrame { private JTable kontenTable; private final IBank bank; import static org.mockito.Mockito.* public KontenApp(IBank bank) { super(quot;Meine Kontenquot;); scenario quot;Leere Kontenliste anzeigenquot;, { this.bank = bank; given quot;eine Bank ohne Kontenquot;, { createLayout(); bank = mock(IBank)} stub(bank.getKonten()).toReturn([]) private void createLayout() { } ... createKontenTable(); when quot;die Konten-Applikation gestartet wirdquot;, { fillKontenTable(); gui = new KontenApp(bank) pack(); gui.setVisible(true) } } private void fillKontenTable() { then quot;dann ist das Konten-Fenster offen quot;, { ((KontenTableModel) kontenTable.getModel()). setKonten(bank.getKonten()); frame = new JFrameOperator(quot;Meine Kontenquot;) } } } and quot;ist die Liste der angezeigten Konten leerquot;, { table = new JTableOperator(frame); table.model.rowCount.shouldBe 0 } }
  • 121. public class KontenApp extends JFrame { private JTable kontenTable; private final IBank bank; import static org.mockito.Mockito.* public KontenApp(IBank bank) { super(quot;Meine Kontenquot;); scenario quot;Leere Kontenliste anzeigenquot;, { this.bank = bank; given quot;eine Bank ohne Kontenquot;, { createLayout(); bank = mock(IBank)} stub(bank.getKonten()).toReturn([]) private void createLayout() { } ... createKontenTable(); when quot;die Konten-Applikation gestartet wirdquot;, { fillKontenTable(); gui = new KontenApp(bank) pack(); gui.setVisible(true) } } private void fillKontenTable() { then quot;dann ist das Konten-Fenster offen quot;, { ((KontenTableModel) kontenTable.getModel()). setKonten(bank.getKonten()); frame = new JFrameOperator(quot;Meine Kontenquot;) } } } and quot;ist die Liste der angezeigten Konten leerquot;, { table = new JTableOperator(frame); table.model.rowCount.shouldBe 0 } gui.dispose() }
  • 122. Dummies und Mocks werden wichtiger
  • 123. Dummies und Mocks werden wichtiger import static org.mockito.Mockito.* scenario quot;Leere Kontenliste anzeigenquot;, { given quot;eine Bank ohne Kontenquot;, { bank = mock(IBank) stub(bank.getKonten()).toReturn([]) } ... }
  • 124. scenario quot;Löschen eines Kontos aus Kontenlistequot;, { given quot;ein offenes Konten-Fenster mit drei Kontenquot;, {...} when quot;das erste Konto angewählt wirdquot;, {...} and quot;der Löschen-Button gedrückt wirdquot;, { deleteButton = new JButtonOperator(frame, quot;Lösche Kontoquot;) deleteButton.push() } then quot;verschwindet das Konto aus der Listequot;, { checkKontenliste(table.model, [[quot;in1quot;, 10], [quot;in2quot;, 20]]) } and quot;wird an der Bank das Konto gelöschtquot;, { ??? } }
  • 125. import static org.easymock.EasyMock.* scenario quot;Löschen eines Kontos aus Kontenlistequot;, { given quot;ein offenes Konten-Fenster mit drei Kontenquot;, {...} when quot;das erste Konto angewählt wirdquot;, {...} and quot;der Löschen-Button gedrückt wirdquot;, { expect(bank.loescheKonto(dreiKonten[0])) deleteButton = new JButtonOperator(frame, quot;Lösche Kontoquot;) deleteButton.push() } then quot;verschwindet das Konto aus der Listequot;, { checkKontenliste(table.model, [[quot;in1quot;, 10], [quot;in2quot;, 20]]) } and quot;wird an der Bank das Konto gelöschtquot;, { verify(bank) } }
  • 126. import static org.mockito.Mockito.* scenario quot;Löschen eines Kontos aus Kontenlistequot;, { given quot;ein offenes Konten-Fenster mit drei Kontenquot;, {...} when quot;das erste Konto angewählt wirdquot;, {...} and quot;der Löschen-Button gedrückt wirdquot;, { deleteButton = new JButtonOperator(frame, quot;Lösche Kontoquot;) deleteButton.push() } then quot;verschwindet das Konto aus der Listequot;, { checkKontenliste(table.model, [[quot;in1quot;, 10], [quot;in2quot;, 20]]) } and quot;wird an der Bank das Konto gelöschtquot;, { verify(bank).loescheKonto(dreiKonten[0]) } }
  • 129. Ziele von Akzeptanztests • Funktionale Tests aus Kundensicht
  • 130. Ziele von Akzeptanztests • Funktionale Tests aus Kundensicht • Sprechen die Sprache des Kunden
  • 131. Ziele von Akzeptanztests • Funktionale Tests aus Kundensicht • Sprechen die Sprache des Kunden • Konkrete Beispiele der Verwendung
  • 132. Ziele von Akzeptanztests • Funktionale Tests aus Kundensicht • Sprechen die Sprache des Kunden • Konkrete Beispiele der Verwendung • Können vom Kunden geschrieben und geändert werden
  • 133. Ziele von Akzeptanztests • Funktionale Tests aus Kundensicht • Sprechen die Sprache des Kunden • Konkrete Beispiele der Verwendung • Können vom Kunden geschrieben und geändert werden • Testen (überwiegend) das System als Ganzes
  • 134. Sind diese Ziele auch mit BDD erreichbar?
  • 135. scenario Gefüllte Kontenliste anzeigen given eine Bank mit drei Konten when die Konten-Applikation gestartet wird then werden im Konten-Fenster drei Konten mit Inhaber und Saldo angezeigt scenario Löschen eines Kontos aus Kontenliste given ein offenes Konten-Fenster mit drei Konten when das erste Konto angewählt wird when der Löschen-Button gedrückt wird then verschwindet das Konto aus der Liste then wird an der Bank das Konto gelöscht
  • 136. Funktionale Tests aus Kundensicht Sprechen die Sprache des Kunden Konkrete Beispiele der Verwendung Können vom Kunden geschrieben und geändert werden Testen (überwiegend) das System als Ganzes
  • 137.  Funktionale Tests aus Kundensicht Sprechen die Sprache des Kunden Konkrete Beispiele der Verwendung Können vom Kunden geschrieben und geändert werden Testen (überwiegend) das System als Ganzes
  • 138.  Funktionale Tests aus Kundensicht  Sprechen die Sprache des Kunden Konkrete Beispiele der Verwendung Können vom Kunden geschrieben und geändert werden Testen (überwiegend) das System als Ganzes
  • 139.  Funktionale Tests aus Kundensicht  Sprechen die Sprache des Kunden  Konkrete Beispiele der Verwendung Können vom Kunden geschrieben und geändert werden Testen (überwiegend) das System als Ganzes
  • 140.  Funktionale Tests aus Kundensicht  Sprechen die Sprache des Kunden  Konkrete Beispiele der Verwendung Können vom Kunden geschrieben und   geändert werden Testen (überwiegend) das System als Ganzes
  • 141.  Funktionale Tests aus Kundensicht  Sprechen die Sprache des Kunden  Konkrete Beispiele der Verwendung Können vom Kunden geschrieben und   geändert werden  Testen (überwiegend) das System als Ganzes
  • 143. BDD ist... • „Richtiges TDD“ leicht(er) gemacht • Veränderung der Sprache • Anpassung der Tools
  • 144. BDD ist... • „Richtiges TDD“ leicht(er) gemacht • Veränderung der Sprache • Anpassung der Tools • Fokus auf Spezifikation und Verhalten
  • 145. BDD ist... • „Richtiges TDD“ leicht(er) gemacht • Veränderung der Sprache • Anpassung der Tools • Fokus auf Spezifikation und Verhalten • Vom Bekannten zum Unbekannten • Dummies und Mocks werden wichtiger
  • 146. BDD ist... • „Richtiges TDD“ leicht(er) gemacht • Veränderung der Sprache • Anpassung der Tools • Fokus auf Spezifikation und Verhalten • Vom Bekannten zum Unbekannten • Dummies und Mocks werden wichtiger • Das Domänenmodell im Mittelpunkt
  • 147. Web-Ressourcen • http://jbehave.org/ • http://www.jdave.org/ • http://rspec.info/ • http://nspec.tigris.org/ • http://www.domaindrivendesign.org/ • http://mockito.org/ • http://jemmy.netbeans.org/