Ohne automatisierte Tests wäre TDD, das Kernstück von XP, undenkbar. Häufig wird auch behauptet, dass Tests das Verhalten des Codes dokumentieren. Doch ist dies tatsächlich der Fall?
Traditionelle Tests überprüfen das Verhalten beispielhaft anhand einiger (hoffentlich) gut gewählter Eingabewerte oder Szenarien. Doch was ist mit Werten, die man beim Schreiben des Tests vergessen hat? Hier fehlt dann nicht nur der Test, sondern auch die Dokumentation!
Testing Tools für funktionale Sprachen, wie z. B. QuickCheck für Haskell, verwenden seit jeher eine komplett andere Herangehensweise. Statt explizit Eingabewerte anzugeben, spezifiziert man charakteristische Eigenschaften des Codes, die unter bestimmten Voraussetzungen gelten sollen. Bei der Testausführung werden diese Eigenschaften dann anhand automatisch generierter Eingabewerte verifiziert.
JUnit bietet seit einiger Zeit die Möglichkeit, solche Eigenschaften als sog. Theories zu formulieren. Was im Vergleich mit QuickCheck und anderen aber fehlt, ist die automatische Erzeugung von Eingabewerten aus einer wie auch immer gearteten Spezifikation heraus. In dieser Session werden zuerst die theoretischen Hintergründe von Spezifikationstechniken angerissen und betrachtet, welche Eigenschaften ein Test braucht, um als gute Spezifikation dienen zu können. Anschließend werden die beiden oben genannten Techniken anhand praktischer Beispiele verglichen, kombiniert und diskutiert.
1. Unit Tests als Spezifikation?
Nicole Rauch, Marc Philipp
26. November 2010
2. Eine einfache Funktion
public double f ( double x ) {
if( x < 5.0 ) return 3.0;
else if( x < 10.0 ) return 2.0;
else return 4.0;
}
Beispielwerte für f: Unit-Tests für f:
@Test public void valuesOfF() {
x f( x ) assertEquals( 3.0, f( 1.0 ), 0.01 );
1 3 assertEquals( 3.0, f( 3.0 ), 0.01 );
3 3 assertEquals( 2.0, f( 7.0 ), 0.01 );
7 2 assertEquals( 4.0, f( 12.0 ), 0.01 );
}
12 4
Nicole Rauch, Marc Philipp Unit Tests als Spezifikation?
3. Eine einfache Funktion
public double f ( double x ) {
if( x < 5.0 ) return 3.0;
else if( x < 10.0 ) return 2.0;
else return 4.0;
}
Beispielwerte für f:
x f( x )
1 3
3 3
7 2
12 4
Nicole Rauch, Marc Philipp Unit Tests als Spezifikation?
4. Was ist das Problem?
„Traditional test suites verify a few well-picked scenarios or example
inputs. However, such example-based testing does not uncover
errors in legal inputs that the test writer overlooked.“
[Saff et.al.]
Nicole Rauch, Marc Philipp Unit Tests als Spezifikation?
5. Eine Alternative: Spezifikationen
Eine geeignete mathematische Spezifikation ist z. B.:
∀x. (x < 5 ⇒ f (x) = 3)
∧ (5 ≤ x < 10 ⇒ f (x) = 2)
∧ (10 ≤ x ⇒ f (x) = 4)
Nicole Rauch, Marc Philipp Unit Tests als Spezifikation?
6. Eine Lösung: JUnit Theories
Herkömmliche Tests benutzen Beispiele:
Überprüfung des Verhaltens unter ausgewählten Eingaben
Entwickler ist dafür verantwortlich, charakteristische Beispiele
zu wählen
Eine Theory verallgemeinert eine Menge von Tests:
Vorbedingung wird explizit angegeben
Assertion muss für alle Eingaben gelten, die die
Vorbedingungen erfüllen
Nicole Rauch, Marc Philipp Unit Tests als Spezifikation?
7. Theories für unsere Funktion
@Theory
public void valuesLessThan5( double x ) {
assumeTrue( x < 5.0 );
assertEquals( 3.0, f(x), 0.01 );
}
@Theory
public void valuesBetween5And10( double x ) {
assumeTrue( 5.0 <= x );
assumeTrue( x < 10.0 );
assertEquals( 2.0, f(x), 0.01 );
}
@Theory
public void values10OrGreater( double x ) {
assumeTrue( 10.0 <= x );
assertEquals( 4.0, f(x), 0.01 );
}
Nicole Rauch, Marc Philipp Unit Tests als Spezifikation?
8. Woher kommen die Eingabewerte?
@DataPoint
public static double VALUE1 = 1.0;
@DataPoint
public static double VALUE2 = 3.0;
@DataPoint
public static double VALUE3 = 7.0;
@DataPoint
public static double VALUE4 = 12.0;
Nicole Rauch, Marc Philipp Unit Tests als Spezifikation?
10. ScalaCheck
Generatoren erzeugen randomisierte Testwerte
Test ist grün nach 100 erfolgreichen Durchläufen
Test ist rot nach 500 unpassenden Eingaben
Nicole Rauch, Marc Philipp Unit Tests als Spezifikation?
11. Das war’s!
Wirklich?
Nicole Rauch, Marc Philipp Unit Tests als Spezifikation?
13. Eine User Story
Als Benutzer möchte ich einer Person
Adressen zuordnen können.
Die Person soll jede Adresse nur
einmal enthalten.
Nicole Rauch, Marc Philipp Unit Tests als Spezifikation?
15. Bob
Bob
Hamburg
Karlsruhe
Bob
Hamburg
Hamburg
Karlsruhe
Nicole Rauch, Marc Philipp Unit Tests als Spezifikation?
16. QuickCheck für Java?
Erste Ansätze
QuickCheck-Portierung [quickcheck.dev.java.net]
Stellt Generatoren für Standardtypen zur Verfügung
Benutzung über for-Schleifen im Unit Test
JCheck [jcheck.org]
Generatoren müssen an jedem Test angegeben werden
Verschachtelte Annotations
Keine Wiederverwendung von Theories
Nicole Rauch, Marc Philipp Unit Tests als Spezifikation?
17. QuickCheck für Java?
Neuer Ansatz
JUnit-QuickCheck
Eleganter neuer Ansatz
Basiert auf JUnit Theories
Parameter werden mit @Forall annotiert
Vordefinierte Generatoren für Standard-Typen
Steckt noch in den Kinderschuhen
Nicole Rauch, Marc Philipp Unit Tests als Spezifikation?
19. Unterschiede
ScalaCheck
Generatoren erzeugen randomisierte Testwerte
Test ist grün nach 100 erfolgreichen Durchläufen
Test ist rot nach 500 unpassenden Eingaben
JUnit-QuickCheck
Generiert pro Parameter 100 Eingabewerte
Bei 2 Parametern 10.000 Kombinationen, bei drei 1.000.000
Test ist grün, wenn alle passenden Eingaben erfolgreich sind
Test ist rot, wenn kein passender Eingabewert gefunden wurde
Nicole Rauch, Marc Philipp Unit Tests als Spezifikation?
20. Fazit
Was macht einen guten Unit Test aus?
Er vermittelt durch Beispiele schnell ein intuitives Verständnis.
Was macht eine gute Spezifikation aus?
Sie beschreibt die zugrundeliegenden Regeln durch Abstraktion.
Geht beides zusammen?
Es gibt kein Entweder-oder; beide Teile sind wichtig.
Nicole Rauch, Marc Philipp Unit Tests als Spezifikation?
21. Das war’s!
Wirklich!
Nicole Rauch, Marc Philipp Unit Tests als Spezifikation?
22. Vielen Dank!
Code & Folien auf GitHub:
https://github.com/marcphilipp/xpdays2010/
Nicole Marc
E-Mail nicole@andrena.de E-Mail marc@andrena.de
Twitter @NicoleRauch Twitter @marcphilipp
Nicole Rauch, Marc Philipp Unit Tests als Spezifikation?