Testgesteuert Entwickeln mit JUnit 4 - Beuth...

21
Testgesteuert Entwickeln mit JUnit 4 Tests „nebenbei“ automatisieren Christoph Knabe Beuth-Hochschule für Technik Berlin Testgesteuert Entwickeln mit JUnit4, © Christoph Knabe 2002, BHT Berlin, FB VI, 2016-10-20, Seite 1/21

Transcript of Testgesteuert Entwickeln mit JUnit 4 - Beuth...

Page 1: Testgesteuert Entwickeln mit JUnit 4 - Beuth Hochschulepublic.beuth-hochschule.de/~knabe/java/junit/...4. Test Driven Development (TDD) Eingeführt ab 1998 von Kent Beck für Smalltalk.Entwicklungszyklus:

Testgesteuert Entwickelnmit JUnit 4

Tests „nebenbei“ automatisieren

Christoph KnabeBeuth-Hochschule für Technik Berlin

Testgesteuert Entwickeln mit JUnit4, © Christoph Knabe 2002, BHT Berlin, FB VI, 2016-10-20, Seite 1/21

Page 2: Testgesteuert Entwickeln mit JUnit 4 - Beuth Hochschulepublic.beuth-hochschule.de/~knabe/java/junit/...4. Test Driven Development (TDD) Eingeführt ab 1998 von Kent Beck für Smalltalk.Entwicklungszyklus:

1. InhaltInhaltsverzeichnis1. Inhalt.....................................................................................................22. Traditionelle Testverfahren........................................................................33. Klassifizierung von Tests...........................................................................54. Test Driven Development (TDD).................................................................65. Beispiel: TDD einer Klasse Stack für Strings.................................................76. Klasse minimal implementieren:.................................................................87. „last in – first out“ (LIFO) testen................................................................98. Ausgabe des LIFO-Tests bei Ausführung:...................................................109. popInvertsPush-Eigenschaft herstellen......................................................1110. Testtreiber ergänzen: Nach 4 push()s und 4 pop()s muss Stack wieder leer sein.........................................................................................................1211. emptyAfterPushsAndPops befriedigen:.....................................................1312. Testtreiber ergänzen: pop() auf leerem Stack läßt ihn leer..........................1413. popOnEmptyDoesNotModify befriedigen:.................................................1514. Round Trip Test....................................................................................1615. Best Practice Quellcodeorganisation........................................................1716. Testtreiber als Lernmittel.......................................................................1817. Test-Suite zum Ausführen von Testtreibern in definierter Reihenfolge...........2018. Fazit...................................................................................................21

Testgesteuert Entwickeln mit JUnit4, © Christoph Knabe 2002, BHT Berlin, FB VI, 2016-10-20, Seite 2/21

Page 3: Testgesteuert Entwickeln mit JUnit 4 - Beuth Hochschulepublic.beuth-hochschule.de/~knabe/java/junit/...4. Test Driven Development (TDD) Eingeführt ab 1998 von Kent Beck für Smalltalk.Entwicklungszyklus:

2. Traditionelle Testverfahren

1. Entwickeln

2. Aufstellen einer Testmatrix mit 3 Spalten - zu tätigende Vorbereitung/Eingabe - erwartete Ausgabe/Reaktion - tatsächliche Ausgabe/Reaktion

3. Manuelles Durchführen vor jedem Release

4. Überarbeiten des Quellcodes

¿? Probleme?Testgesteuert Entwickeln mit JUnit4, © Christoph Knabe 2002, BHT Berlin, FB VI, 2016-10-20, Seite 3/21

Page 4: Testgesteuert Entwickeln mit JUnit 4 - Beuth Hochschulepublic.beuth-hochschule.de/~knabe/java/junit/...4. Test Driven Development (TDD) Eingeführt ab 1998 von Kent Beck für Smalltalk.Entwicklungszyklus:

Probleme traditioneller Testverfahren

Tests spät im Phasenmodell oft Budget erschöpft

Spezifische Codeteile wie Fehlerbehandlung schwer über Oberfläche ansteuerbar Tests kleinerer Einheiten nötig!Bsp.: Test von Datenbankschreiben bei voller Platte

Keine Garantie, dass alle Codeteile getestet werden Tests kleinerer Einheiten nötig!

Manuelle Testdurchführung sehr aufwändig - selten machbar (unagil)- Fehler aufgrund Ermüdung

Testgesteuert Entwickeln mit JUnit4, © Christoph Knabe 2002, BHT Berlin, FB VI, 2016-10-20, Seite 4/21

Page 5: Testgesteuert Entwickeln mit JUnit 4 - Beuth Hochschulepublic.beuth-hochschule.de/~knabe/java/junit/...4. Test Driven Development (TDD) Eingeführt ab 1998 von Kent Beck für Smalltalk.Entwicklungszyklus:

3. Klassifizierung von Tests

Nach Größe des Getesteten:- Eine Unit (z.B. Klasse) isoliert: Unit-Test- Mehrere Units im Zusammenspiel: Integrationstest- Gesamtsystem über Oberfläche: AkzeptanztestNach Testabdeckung von:- Ablaufzweigen- Ablaufbedingungen- AblaufpfadenNach AutomationNach Wiederholung: einmalig, Regressionstest

Testgesteuert Entwickeln mit JUnit4, © Christoph Knabe 2002, BHT Berlin, FB VI, 2016-10-20, Seite 5/21

Page 6: Testgesteuert Entwickeln mit JUnit 4 - Beuth Hochschulepublic.beuth-hochschule.de/~knabe/java/junit/...4. Test Driven Development (TDD) Eingeführt ab 1998 von Kent Beck für Smalltalk.Entwicklungszyklus:

4. Test Driven Development (TDD)

Eingeführt ab 1998 von Kent Beck für Smalltalk.Entwicklungszyklus:1. Testtreiber programmieren, der gewünschtes Verhalten prüft.2. Ausführen Testtreiber+Testling: Sollte Fehler feststellen.3. Testling erweitern/korrigieren bis Fehler weg.Vorteile:- umfangreiche Testsuite „nebenbei“- hohe Testabdeckung- Es entstehen nur testbare Units.

Testgesteuert Entwickeln mit JUnit4, © Christoph Knabe 2002, BHT Berlin, FB VI, 2016-10-20, Seite 6/21

Page 7: Testgesteuert Entwickeln mit JUnit 4 - Beuth Hochschulepublic.beuth-hochschule.de/~knabe/java/junit/...4. Test Driven Development (TDD) Eingeführt ab 1998 von Kent Beck für Smalltalk.Entwicklungszyklus:

5. Beispiel: TDD einer Klasse Stack für Strings

Klasse spezifizieren

/**Stack of Strings according to the "Last In - First Out" (LIFO) principle.*/public interface Stack {

/**Puts element onto the stack*/ void push(String element);

/**Returns and removes the oldest element of the stack. @throws EmptyExc No element is on the stack*/ String pop() throws EmptyExc;

/**No element is on the stack*/ public class EmptyExc extends Exception {}

}Testgesteuert Entwickeln mit JUnit4, © Christoph Knabe 2002, BHT Berlin, FB VI, 2016-10-20, Seite 7/21

Page 8: Testgesteuert Entwickeln mit JUnit 4 - Beuth Hochschulepublic.beuth-hochschule.de/~knabe/java/junit/...4. Test Driven Development (TDD) Eingeführt ab 1998 von Kent Beck für Smalltalk.Entwicklungszyklus:

6. Klasse minimal implementieren:

public class StackImpl implements Stack {

@Overridepublic void push(final String element) {}

@Overridepublic String pop() throws EmptyExc {

return null;}

}

¿? Fehlt hier was?

Testgesteuert Entwickeln mit JUnit4, © Christoph Knabe 2002, BHT Berlin, FB VI, 2016-10-20, Seite 8/21

Page 9: Testgesteuert Entwickeln mit JUnit 4 - Beuth Hochschulepublic.beuth-hochschule.de/~knabe/java/junit/...4. Test Driven Development (TDD) Eingeführt ab 1998 von Kent Beck für Smalltalk.Entwicklungszyklus:

7. „last in – first out“ (LIFO) testenimport static org.junit.Assert.*;import org.junit.Test;public class StackTest {

private final Stack stack = new StackImpl();

@Test public void popInvertsPush()throws Exception {final String[] elements = {"", "a", "XY", "749398"};//Push all:for(final String string: elements){

stack.push(string);}//Pop all and compare:for(int i=elements.length-1; i>=0; i--){

assertEquals(elements[i], stack.pop());}

}}

Testgesteuert Entwickeln mit JUnit4, © Christoph Knabe 2002, BHT Berlin, FB VI, 2016-10-20, Seite 9/21

Page 10: Testgesteuert Entwickeln mit JUnit 4 - Beuth Hochschulepublic.beuth-hochschule.de/~knabe/java/junit/...4. Test Driven Development (TDD) Eingeführt ab 1998 von Kent Beck für Smalltalk.Entwicklungszyklus:

8. Ausgabe des LIFO-Tests bei Ausführung:

There was 1 failure:1) popInvertsPush(StackTest)java.lang.AssertionError: expected:<749398> but was:<null> at org.junit.Assert.fail(Assert.java:71) ... at org.junit.Assert.assertEquals(Assert.java:116) at StackTest.popInvertsPush(StackTest.java:26)

Testgesteuert Entwickeln mit JUnit4, © Christoph Knabe 2002, BHT Berlin, FB VI, 2016-10-20, Seite 10/21

Page 11: Testgesteuert Entwickeln mit JUnit 4 - Beuth Hochschulepublic.beuth-hochschule.de/~knabe/java/junit/...4. Test Driven Development (TDD) Eingeführt ab 1998 von Kent Beck für Smalltalk.Entwicklungszyklus:

9. popInvertsPush-Eigenschaft herstellen

private final String[] entries = new String[10];private int fill = 0;

@Overridepublic void push(final String element) {

entries[fill] = element;fill++;

}

@Overridepublic String pop() throws EmptyExc {

fill--;return entries[fill];

}

¿? So korrekte Implementierung?Testgesteuert Entwickeln mit JUnit4, © Christoph Knabe 2002, BHT Berlin, FB VI, 2016-10-20, Seite 11/21

Page 12: Testgesteuert Entwickeln mit JUnit 4 - Beuth Hochschulepublic.beuth-hochschule.de/~knabe/java/junit/...4. Test Driven Development (TDD) Eingeführt ab 1998 von Kent Beck für Smalltalk.Entwicklungszyklus:

10. Testtreiber ergänzen: Nach 4 push()s und 4 pop()s muss Stack wieder leer sein

@Test public void emptyAfterPushsAndPops()throws Exception{ popInvertsPush(); try{ stack.pop(); fail("Stack.EmptyExc expected"); } catch ( Stack.EmptyExc expected ){}}Test-Ausgabe von JUnit:There was 1 failure:1) emptyAfterPushsAndPops(StackTest)java.lang.ArrayIndexOutOfBoundsException: -1 at Stack.pop(Stack.java:16) at StackTest.emptyAfterPushsAndPops(StackTest.java:33)

Testgesteuert Entwickeln mit JUnit4, © Christoph Knabe 2002, BHT Berlin, FB VI, 2016-10-20, Seite 12/21

Page 13: Testgesteuert Entwickeln mit JUnit 4 - Beuth Hochschulepublic.beuth-hochschule.de/~knabe/java/junit/...4. Test Driven Development (TDD) Eingeführt ab 1998 von Kent Beck für Smalltalk.Entwicklungszyklus:

11. emptyAfterPushsAndPops befriedigen:

Vor dem fehlgeschlagenen Array-Zugriff bauen wir eine Wächterklausel1 ein.

@Overridepublic String pop() throws EmptyExc { fill--; if(fill<0){ //Wächterklausel throw new EmptyExc(); } return entries[fill];}

¿? So korrekte Implementierung?

1 http://c2.com/cgi/wiki?GuardClause

Testgesteuert Entwickeln mit JUnit4, © Christoph Knabe 2002, BHT Berlin, FB VI, 2016-10-20, Seite 13/21

Page 14: Testgesteuert Entwickeln mit JUnit 4 - Beuth Hochschulepublic.beuth-hochschule.de/~knabe/java/junit/...4. Test Driven Development (TDD) Eingeführt ab 1998 von Kent Beck für Smalltalk.Entwicklungszyklus:

12. Testtreiber ergänzen: pop() auf leerem Stack läßt ihn leer@Test public void popOnEmptyDoesNotModify()throws Stack.EmptyExc { try{stack.pop(); fail("Stack.EmptyExc expected");} catch(Stack.EmptyExc expected){} popInvertsPush(); try{stack.pop(); fail("Stack.EmptyExc expected");} catch(Stack.EmptyExc expected){}}

Test-Ausgabe von JUnit:There was 1 failure:1) popOnEmptyDoesNotModify(StackTest)java.lang.ArrayIndexOutOfBoundsException: -1 at Stack.push(Stack.java:7) at StackTest.popInvertsPush(StackTest.java:22) at StackTest.popOnEmptyDoesNotModify(StackTest.java:41)

Testgesteuert Entwickeln mit JUnit4, © Christoph Knabe 2002, BHT Berlin, FB VI, 2016-10-20, Seite 14/21

Page 15: Testgesteuert Entwickeln mit JUnit 4 - Beuth Hochschulepublic.beuth-hochschule.de/~knabe/java/junit/...4. Test Driven Development (TDD) Eingeführt ab 1998 von Kent Beck für Smalltalk.Entwicklungszyklus:

13. popOnEmptyDoesNotModify befriedigen:

@Overridepublic String pop() throws EmptyExc { if(fill<=0){ //Wächterklausel vorgezogen throw new EmptyExc(); } fill--; return entries[fill];}

Jetzt verhält sich der Stack korrekt. Kein weiterer Änderungsbedarf.

Testgesteuert Entwickeln mit JUnit4, © Christoph Knabe 2002, BHT Berlin, FB VI, 2016-10-20, Seite 15/21

Page 16: Testgesteuert Entwickeln mit JUnit 4 - Beuth Hochschulepublic.beuth-hochschule.de/~knabe/java/junit/...4. Test Driven Development (TDD) Eingeführt ab 1998 von Kent Beck für Smalltalk.Entwicklungszyklus:

14. Round Trip Test

Eine reine Funktion (ohne Seiteneffekt) kann man für sich testen.

Methoden eines Objektes mit Gedächtnis nur im Zusammenspiel testbar: Bei popInvertsPush() wird Stack erst mit push gefüllt, dann mit pop ausgelesen.

Bei Datenbanktests sollte Hineinschreiben und Auslesen in verschiedenen Transaktionen erfolgen!

Testgesteuert Entwickeln mit JUnit4, © Christoph Knabe 2002, BHT Berlin, FB VI, 2016-10-20, Seite 16/21

Page 17: Testgesteuert Entwickeln mit JUnit 4 - Beuth Hochschulepublic.beuth-hochschule.de/~knabe/java/junit/...4. Test Driven Development (TDD) Eingeführt ab 1998 von Kent Beck für Smalltalk.Entwicklungszyklus:

15. Best Practice Quellcodeorganisation

Testsuite in eigenem Verzeichnisbaum unter src/testparallel zum Produktverzeichnisbaum unter src/main.

Maven führt bei mvn test alle Klassen, deren Name auf Test endet, als Testtreiber aus.Eclipse führt mittels MausRechts > Run As > JUnit Test alle Testtreiber im Verzeichnis aus.

☞ Projekt Aufgabenplaner Testsuite ausführen - in Maven - in IDE.¿? Lernen: Wie Regular Expression für E-Mail-Adr.?

Testgesteuert Entwickeln mit JUnit4, © Christoph Knabe 2002, BHT Berlin, FB VI, 2016-10-20, Seite 17/21

Page 18: Testgesteuert Entwickeln mit JUnit 4 - Beuth Hochschulepublic.beuth-hochschule.de/~knabe/java/junit/...4. Test Driven Development (TDD) Eingeführt ab 1998 von Kent Beck für Smalltalk.Entwicklungszyklus:

16. Testtreiber als LernmittelBsp.: Lernen von Regular Expressions

Schreiben mehrerer Testfälle:

Zeichenkette als eMail-Adresse Korrekt?Franz Nein@ NeinFranz@ NeinFranz@hallo Nein (?)[email protected] [email protected] Jafranz@hallo. de Nein

Testgesteuert Entwickeln mit JUnit4, © Christoph Knabe 2002, BHT Berlin, FB VI, 2016-10-20, Seite 18/21

Page 19: Testgesteuert Entwickeln mit JUnit 4 - Beuth Hochschulepublic.beuth-hochschule.de/~knabe/java/junit/...4. Test Driven Development (TDD) Eingeführt ab 1998 von Kent Beck für Smalltalk.Entwicklungszyklus:

Email-Muster-Testfälle in JUnitpublic class EMailTest extends Assert {

private static final Pattern emailPattern = Pattern.compile("?");

@Test public void eMailAdressen(){ assertEmail("Franz@hallo", true); assertEmail("[email protected]", true); assertEmail("[email protected]", true); assertEmail("Franz", false); assertEmail("Franz@", false); assertEmail("hallo.de", false); assertEmail("franz@hallo .de", false); }

private void assertEmail(final String toCheck, boolean isEmail){ final Matcher m = emailPattern.matcher(toCheck); assertEquals(isEmail, m.matches()); }}

Testgesteuert Entwickeln mit JUnit4, © Christoph Knabe 2002, BHT Berlin, FB VI, 2016-10-20, Seite 19/21

Page 20: Testgesteuert Entwickeln mit JUnit 4 - Beuth Hochschulepublic.beuth-hochschule.de/~knabe/java/junit/...4. Test Driven Development (TDD) Eingeführt ab 1998 von Kent Beck für Smalltalk.Entwicklungszyklus:

17. Test-Suite zum Ausführen von Testtreibern in definierter Reihenfolge

package fb6._any.ut;import org.junit.runner.RunWith;import org.junit.runners.Suite;

/**Testsuite zum zusammengefassten Ausführen bestimmter Tests.*/@RunWith (Suite.class)@Suite.SuiteClasses ({ FileUtilTest.class, StringUtilTest.class})public class TestsAnyUt {}

Testgesteuert Entwickeln mit JUnit4, © Christoph Knabe 2002, BHT Berlin, FB VI, 2016-10-20, Seite 20/21

Page 21: Testgesteuert Entwickeln mit JUnit 4 - Beuth Hochschulepublic.beuth-hochschule.de/~knabe/java/junit/...4. Test Driven Development (TDD) Eingeführt ab 1998 von Kent Beck für Smalltalk.Entwicklungszyklus:

18. Fazit

Testfälle erhöhen die Programmqualität.

Reproduzierbare Testfälle erleichtern Änderungen am Code.

„Test First“ (erst Testtreiber schreiben, dann befriedigen) erhöht die Testabdeckung und damit die Qualität und Änderungsfreundlichkeit.

JUnit ist das bewährteste Framework zur Testautomation, vielfach kopiert.

Testgesteuert Entwickeln mit JUnit4, © Christoph Knabe 2002, BHT Berlin, FB VI, 2016-10-20, Seite 21/21