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 O...
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

    ...
Regressionstests       Inkrementelles Vorgehen

                   Entkopplung
    Designfokus
                         Sc...
Regressionstests       Inkrementelles Vorgehen

                   Entkopplung
    Designfokus
                         Sc...
Regressionstests       Inkrementelles Vorgehen

                    Entkopplung
    Designfokus
                          ...
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...
Wo fange ich an?

     Wie nenne ich die
       Testklasse?


  Typische TDD-Fragen
 Wie nenne ich die
  Testmethode?


  ...
Wo fange ich an?

     Wie nenne ich die
       Testklasse?       Wie viele Assertions
                            pro Tes...
Wo fange ich an?            Welche Objekte
                         erzeuge ich im Setup?
     Wie nenne ich die
       Te...
Wo fange ich an?            Welche Objekte
                         erzeuge ich im Setup?
     Wie nenne ich die
       Te...
Wo fange ich an?              Welche Objekte
                           erzeuge ich im Setup?
     Wie nenne ich die
     ...
Schwammige Regeln
Heuristiken
Beispiel...
public class KontoTest {
	 @Test
	 public void neuesKonto() {
	 	 Konto konto = new Konto(quot;Johannesquot;);
	 	 assertE...
public class KontoTest...
	 private Konto konto;
	   @Before
	   public void init() {
	   	 konto = new Konto(quot;Johanne...
public class KontoTest...
	 @Test
	 public void einzahlung() {
	 	 konto.zahleEin(100);
	 	 assertEquals(100, konto.getSal...
public class KontoTest...
	 @Test
	 public void einzahlung() {
	 	 konto.zahleEin(100);
	 	 assertEquals(100, konto.getSal...
public class KontoTest...
	 @Test
	 public void einzahlung() {
	 	 konto.zahleEin(100);
	 	 assertEquals(100, konto.getSal...
public class NeuesKontoTest...
	 @Test public void inhaber()...
	 @Test public void anfangssaldo()...
	 @Test public void ...
Gewünschtes
         Kontoverhalten
• Ein neues Konto
  • soll den Namen seines Inhabers mitteilen
      können
    • soll...
public class EinNeuesKonto...
	 @Test public void sollInhaberLiefern()...
	 @Test public void sollAnfangssaldoNullHaben()....
public class EinNeuesKonto...
	 @Test public void sollInhaberLiefern()...
	 @Test public void sollAnfangssaldoNullHaben()....
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 versu...
Die Sprache des Testen

Testfälle, Testen, Beweisen,
Sicherstellen, Programmeinheit,
Korrektheit, Vorbedingungen
Wir versu...
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...
Die Sprache des BDD

User Stories, Szenario,
Spezifikation,Verhalten, Kontext
Wir spezifizieren in Szenarien, wie sich
Dinge...
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;
	 @S...
GSpec
http://groovy.codehaus.org/
Using+GSpec+with+Groovy
def ein = new GSpecBuilderRunner()
ein.context('Ein neues Konto') {
    def INHABER = quot;Johannesquot;	
    initially {
...
def ein = new GSpecBuilderRunner()
ein.context('Ein neues Konto') {
    def INHABER = quot;Johannesquot;	
    initially {
...
easyb
http://www.easyb.org/
scenario quot;Konto mit ANFANGSSALDOquot;, {
	 def ANFANGSSALDO = 42
	 def BETRAG = 101
	 given quot;ein Konto mit SALDOqu...
scenario quot;Konto mit ANFANGSSALDOquot;, {
	 def ANFANGSSALDO = 42
	 def BETRAG = 101
	 given quot;ein Konto mit SALDOqu...
Veränderter Fokus
Veränderter Fokus
• Weg vom Wie - hin zum Was
  • User Stories -> Szenarios
  • Anfangszustand pro Szenario
  • Einzelne Z...
Veränderter Fokus
• Weg vom Wie - hin zum Was
  • User Stories -> Szenarios
  • Anfangszustand pro Szenario
  • Einzelne Z...
Veränderter Fokus
• Weg vom Wie - hin zum Was
  • User Stories -> Szenarios
  • Anfangszustand pro Szenario
  • Einzelne Z...
„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 gesta...
Story: konten gui

scenario Leere Kontenliste anzeigen
   given eine Bank ohne Konten
   when die Konten-Applikation gesta...
Story: konten gui

scenario Leere Kontenliste anzeigen
   given eine Bank ohne Konten
   when die Konten-Applikation gesta...
scenario quot;Leere Kontenliste anzeigenquot;, {
	 given quot;eine Bank ohne Kontenquot;
	 when quot;die Konten-Applikatio...
scenario quot;Leere Kontenliste anzeigenquot;, {
	 given quot;eine Bank ohne Kontenquot;, {
	 	 bank = new Bank()
	 }
	 wh...
import static org.mockito.Mockito.*
scenario quot;Leere Kontenliste anzeigenquot;, {
	 given quot;eine Bank ohne Kontenquo...
import static org.mockito.Mockito.*
scenario quot;Leere Kontenliste anzeigenquot;, {
	 given quot;eine Bank ohne Kontenquo...
import static org.mockito.Mockito.*
scenario quot;Leere Kontenliste anzeigenquot;, {
	 given quot;eine Bank ohne Kontenquo...
import static org.mockito.Mockito.*
scenario quot;Leere Kontenliste anzeigenquot;, {
	 given quot;eine Bank ohne Kontenquo...
import static org.mockito.Mockito.*
scenario quot;Leere Kontenliste anzeigenquot;, {
	 given quot;eine Bank ohne Kontenquo...
import static org.mockito.Mockito.*
scenario quot;Leere Kontenliste anzeigenquot;, {
	 given quot;eine Bank ohne Kontenquo...
import static org.mockito.Mockito.*
scenario quot;Leere Kontenliste anzeigenquot;, {
	 given quot;eine Bank ohne Kontenquo...
import static org.mockito.Mockito.*
scenario quot;Leere Kontenliste anzeigenquot;, {
	 given quot;eine Bank ohne Kontenquo...
import static org.mockito.Mockito.*
scenario quot;Leere Kontenliste anzeigenquot;, {
	 given quot;eine Bank ohne Kontenquo...
public class KontenApp extends JFrame {
                         	   private JTable kontenTable;
                         ...
public class KontenApp extends JFrame {
                         	   private JTable kontenTable;
                         ...
Dummies und Mocks
 werden wichtiger
Dummies und Mocks
 werden wichtiger
import static org.mockito.Mockito.*
scenario quot;Leere Kontenliste anzeigenquot;, {
	...
scenario quot;Löschen eines Kontos aus Kontenlistequot;, {
	 given quot;ein offenes Konten-Fenster mit drei Kontenquot;, {...
import static org.easymock.EasyMock.*
scenario quot;Löschen eines Kontos aus Kontenlistequot;, {
	 given quot;ein offenes ...
import static org.mockito.Mockito.*
scenario quot;Löschen eines Kontos aus Kontenlistequot;, {
	 given quot;ein offenes Ko...
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 Ve...
Ziele von Akzeptanztests
• Funktionale Tests aus Kundensicht
• Sprechen die Sprache des Kunden
• Konkrete Beispiele der Ve...
Ziele von Akzeptanztests
• Funktionale Tests aus Kundensicht
• Sprechen die Sprache des Kunden
• Konkrete Beispiele der Ve...
Sind diese Ziele auch
mit BDD erreichbar?
scenario Gefüllte Kontenliste
         anzeigen
    given eine Bank mit drei Konten
    when die Konten-Applikation
      ...
Funktionale Tests aus Kundensicht
Sprechen die Sprache des Kunden
Konkrete Beispiele der Verwendung
Können vom Kunden gesc...
 Funktionale Tests aus Kundensicht
  Sprechen die Sprache des Kunden
  Konkrete Beispiele der Verwendung
  Können vom Kun...
 Funktionale Tests aus Kundensicht
 Sprechen die Sprache des Kunden
  Konkrete Beispiele der Verwendung
  Können vom Kun...
 Funktionale Tests aus Kundensicht
 Sprechen die Sprache des Kunden
 Konkrete Beispiele der Verwendung
  Können vom Kun...
 Funktionale Tests aus Kundensicht
   Sprechen die Sprache des Kunden
   Konkrete Beispiele der Verwendung
    Können v...
 Funktionale Tests aus Kundensicht
   Sprechen die Sprache des Kunden
   Konkrete Beispiele der Verwendung
    Können v...
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 Spezifikat...
BDD ist...

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

• „Richtiges TDD“ leicht(er) gemacht
  • Veränderung der Sprache
  • Anpassung der Tools
• Fokus auf Spezifikat...
Web-Ressourcen
• http://jbehave.org/
• http://www.jdave.org/
• http://rspec.info/
• http://nspec.tigris.org/
• http://www....
Fragen und
Anmerkungen?
Behaviour-Driven Development
Behaviour-Driven Development
Behaviour-Driven Development
Nächste SlideShare
Wird geladen in …5
×

Behaviour-Driven Development

5.710 Aufrufe

Veröffentlicht am

A talk given in german about BDD, its relationship to TDD and some of the tools available for behaviour-driving Java code.

Veröffentlicht in: Technologie
0 Kommentare
3 Gefällt mir
Statistik
Notizen
  • Als Erste(r) kommentieren

Keine Downloads
Aufrufe
Aufrufe insgesamt
5.710
Auf SlideShare
0
Aus Einbettungen
0
Anzahl an Einbettungen
15
Aktionen
Geteilt
0
Downloads
0
Kommentare
0
Gefällt mir
3
Einbettungen 0
Keine Einbettungen

Keine Notizen für die Folie

Behaviour-Driven Development

  1. 1. 2. Juni 2008
  2. 2. Johannes Link
  3. 3. Heidelberg
  4. 4. Mein eigener Chef
  5. 5. Mein eigener Chef (Extremer) Softwareentwickler
  6. 6. Mein eigener Chef (Extremer) Softwareentwickler (Agiler) Coach
  7. 7. Mein eigener Chef (Extremer) Softwareentwickler (Agiler) Coach Testgetrieben
  8. 8. johanneslink.net
  9. 9. Behaviour Driven Development
  10. 10. Behaviour Driven Development Was. Warum. Wie.
  11. 11. TDD
  12. 12. Testgetriebene Entwicklung
  13. 13. Test / Code / Refactor Tests Fail Tests OK
  14. 14. Test / Code / Refactor 1) Test hinzufügen Tests Fail Tests OK
  15. 15. Test / Code / Refactor 1) Test hinzufügen Tests Fail Tests OK 2) Test erfüllen
  16. 16. Test / Code / Refactor 1) Test hinzufügen 3) Code Tests Fail Tests OK vereinfachen 2) Test erfüllen
  17. 17. Warum TDD?
  18. 18. Regressionstests Warum TDD?
  19. 19. Regressionstests Weniger Bugs Warum TDD?
  20. 20. Regressionstests Inkrementelles Vorgehen Weniger Bugs Warum TDD?
  21. 21. Regressionstests Inkrementelles Vorgehen Designfokus Weniger Bugs Warum TDD?
  22. 22. Regressionstests Inkrementelles Vorgehen Entkopplung Designfokus Weniger Bugs Warum TDD?
  23. 23. Regressionstests Inkrementelles Vorgehen Entkopplung Designfokus Schnittstellen Weniger Bugs Warum TDD?
  24. 24. Regressionstests Inkrementelles Vorgehen Entkopplung Designfokus Schnittstellen Weniger Bugs Warum TDD? Ausführbare Spezifikation?
  25. 25. Regressionstests Inkrementelles Vorgehen Entkopplung Designfokus Schnittstellen Weniger Bugs Warum TDD? Ausführbare Spezifikation? Technische Dokumentation?
  26. 26. Typische TDD-Fragen
  27. 27. Wo fange ich an? Typische TDD-Fragen
  28. 28. Wo fange ich an? Typische TDD-Fragen Wo höre ich auf?
  29. 29. Wo fange ich an? Wie nenne ich die Testklasse? Typische TDD-Fragen Wo höre ich auf?
  30. 30. Wo fange ich an? Wie nenne ich die Testklasse? Typische TDD-Fragen Wie nenne ich die Testmethode? Wo höre ich auf?
  31. 31. 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?
  32. 32. 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?
  33. 33. 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?
  34. 34. 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?
  35. 35. Schwammige Regeln
  36. 36. Heuristiken
  37. 37. Beispiel...
  38. 38. public class KontoTest { @Test public void neuesKonto() { Konto konto = new Konto(quot;Johannesquot;); assertEquals(quot;Johannesquot;, konto.getInhaber()); assertEquals(0, konto.getSaldo()); } }
  39. 39. 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()); }
  40. 40. 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); }
  41. 41. 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); }
  42. 42. 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); }
  43. 43. 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); }
  44. 44. 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
  45. 45. 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()...
  46. 46. 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()...
  47. 47. Dan North
  48. 48. http://dannorth.net/introducing-bdd
  49. 49. BDD: Vom Test zum Verhalten
  50. 50. Die Sprache beeinflusst unser Verhalten
  51. 51. Die Sprache des Testen
  52. 52. Die Sprache des Testen Testfälle, Testen, Beweisen, Sicherstellen, Programmeinheit, Korrektheit, Vorbedingungen
  53. 53. 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
  54. 54. 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
  55. 55. Die Sprache des BDD
  56. 56. Die Sprache des BDD User Stories, Szenario, Spezifikation,Verhalten, Kontext
  57. 57. 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
  58. 58. 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
  59. 59. Wie funktioniert meine Klasse?
  60. 60. Wie funktioniert meine Klasse?
  61. 61. Wie funktioniert meine Klasse? Was soll mein Programm tun?
  62. 62. JBehave Instinct JDave Werkzeuge GSpec easyb RSpec NSpec
  63. 63. Instinct http://code.google.com/p/instinct/
  64. 64. @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); } }
  65. 65. GSpec http://groovy.codehaus.org/ Using+GSpec+with+Groovy
  66. 66. 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''') {..} }
  67. 67. 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
  68. 68. easyb http://www.easyb.org/
  69. 69. 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() } } }
  70. 70. 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 }
  71. 71. Veränderter Fokus
  72. 72. Veränderter Fokus • Weg vom Wie - hin zum Was • User Stories -> Szenarios • Anfangszustand pro Szenario • Einzelne Zusicherungen
  73. 73. 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
  74. 74. 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
  75. 75. „Prozess“
  76. 76. Naives TDD
  77. 77. JDK
  78. 78. Technik JDK
  79. 79. Domänenmodell Technik JDK
  80. 80. Applikationsmodell Domänenmodell Technik JDK
  81. 81. Benutzerschnittstelle Applikationsmodell Domänenmodell Technik JDK
  82. 82. Anforderungen Benutzerschnittstelle Applikationsmodell Domänenmodell Technik JDK
  83. 83. Von Außen nach Innen
  84. 84. Von Außen nach Innen Vom Bekannten zum Unbekannten
  85. 85. JDK
  86. 86. Anforderungen JDK
  87. 87. Anforderungen Benutzerschnittstelle JDK
  88. 88. Anforderungen Benutzerschnittstelle Applikationsmodell JDK
  89. 89. Anforderungen Benutzerschnittstelle Applikationsmodell Domänenmodell JDK
  90. 90. Anforderungen Benutzerschnittstelle Applikationsmodell Domänenmodell Technik JDK
  91. 91. JDK
  92. 92. Anforderungen JDK
  93. 93. Anforderungen Domänenmodell JDK
  94. 94. Anforderungen Benutzerschnittstelle Domänenmodell JDK
  95. 95. Anforderungen Benutzerschnittstelle Applikationsmodell Domänenmodell JDK
  96. 96. Anforderungen Benutzerschnittstelle Applikationsmodell Domänenmodell Technik JDK
  97. 97. Domänenmodell
  98. 98. Anforderungen Domänenmodell
  99. 99. Anforderungen Domänenmodell Domänen- analyse
  100. 100. Domain Driven Design Eric Evans
  101. 101. Beispiel: Konten-GUI
  102. 102. Story: konten gui
  103. 103. 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
  104. 104. 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
  105. 105. 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
  106. 106. 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; }
  107. 107. 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; }
  108. 108. 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; }
  109. 109. 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 { }
  110. 110. 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; }
  111. 111. 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(); }
  112. 112. 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; }
  113. 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;, { 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) { } } }
  114. 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;, { 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; }
  115. 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;, { 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;); } }
  116. 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;, { frame = new JFrameOperator(quot;Meine Kontenquot;) } and quot;ist die Liste der angezeigten Konten leerquot;, { table = new JTableOperator(frame); table.model.rowCount.shouldBe 0 } }
  117. 117. 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 } }
  118. 118. 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() }
  119. 119. Dummies und Mocks werden wichtiger
  120. 120. 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([]) } ... }
  121. 121. 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;, { ??? } }
  122. 122. 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) } }
  123. 123. 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]) } }
  124. 124. Macht BDD Akzeptanztests überflüssig?
  125. 125. Ziele von Akzeptanztests
  126. 126. Ziele von Akzeptanztests • Funktionale Tests aus Kundensicht
  127. 127. Ziele von Akzeptanztests • Funktionale Tests aus Kundensicht • Sprechen die Sprache des Kunden
  128. 128. Ziele von Akzeptanztests • Funktionale Tests aus Kundensicht • Sprechen die Sprache des Kunden • Konkrete Beispiele der Verwendung
  129. 129. 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
  130. 130. 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
  131. 131. Sind diese Ziele auch mit BDD erreichbar?
  132. 132. 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
  133. 133. 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. 134.  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
  135. 135.  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
  136. 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. 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. 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. 139. BDD ist...
  140. 140. BDD ist... • „Richtiges TDD“ leicht(er) gemacht • Veränderung der Sprache • Anpassung der Tools
  141. 141. BDD ist... • „Richtiges TDD“ leicht(er) gemacht • Veränderung der Sprache • Anpassung der Tools • Fokus auf Spezifikation und Verhalten
  142. 142. 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
  143. 143. 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
  144. 144. 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/
  145. 145. Fragen und Anmerkungen?

×