Behaviour-Driven Development

5,785 views

Published on

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

Published in: Technology
0 Comments
3 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
5,785
On SlideShare
0
From Embeds
0
Number of Embeds
15
Actions
Shares
0
Downloads
0
Comments
0
Likes
3
Embeds 0
No embeds

No notes for slide

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?

×