Testdaten-Provider
Um einen parametrisierte Test-Methode mit Daten zu versorgen bieten sich Methoden als Testdaten-Provider an.
Eine solcher Provider-Methode liefert einen Stream
von Testdaten-Sätzen. Ein Testdaten-Satz besteht in der Regel
auf mehreren Einzeldaten, er kann aber natürlich auch aus einem einzelnen Datum bestehen. Jeder Satz ist in
ein Arguments
-Objekt verpackt und besteht daher immer aus Objekten; Daten atomarer Typen werden dabei in
Objekte der korrespondierenden Klassen verpackt.
Betrachten wir eine einfache Test-Methode die für die Ausführung zwei Strings benötigt.
Wie jede Test-Methode die eine nichtleere Parameterliste hat, muß sie mit der Annotation @ParameterizedTest
versehen sein:
@ParameterizedTest void passwortWirdNichtAkzeptiert(String passwort, String grund) { assertThat(policy.validate(passwort)).as(grund).isFalse(); }
Variante 1: die statische Methode
Der einfachste Weg einen Testdaten-Provider zu definieren führt über eine statische Methode die sich in der selben Klasse befindet wie die Test-Methode:
static Stream<Arguments> pwdWirdNichtAkzeptiert() { return Stream.of( Arguments.of("Hallo", "nur Buchstaben"), Arguments.of("1234567", "nur Ziffern"), Arguments.of("!%#&/()", "nur Sonderzeichen") ); }
Stimmt der Name des Testdaten-Providers mit dem Namen der Test-Methode überein, kann man den Parameter in der Annotation auch weglassen. Für diese Variante gelten folgende Einschränkungen:
- Die Methode muß in der gleichen Klasse liegen wie die Test-Methode
- Die Methode muß als
static
deklariert sein - Die Methode darf nicht
private
deklariert sein
Variante 2: die qualifizierte statische Methode
Nachteil der ersten Variante ist, daß sich der Testdaten-Provider in der gleichen Klasse befinden muß
wie die Test-Methode. Das gilt auch, wenn sich die Methode in einer Member Class oder einer Inner Class befindet.
Damit lassen sich keine Testdaten-Provider definieren, die von mehreren geschachtelte Test-Klassen
-- per Annotation @Nested
-- gemeinsam genutzt werden.
Befindet sich der Testdaten-Provider in einer anderen Klasse als die Test-Methode, kann man zusätzlich zur Methode
die Klasse angeben in der sich die Methode befindet. Die Package-Angabe muß voll qualifiziert sein, die Methode
wird mit #
getrennt angefügt:
MethodSource("org.mletkin.unittest.TestDaten#pwdWirdNichtAkzeptiert")
Wie in Variante 1 erfolgt die Angabe in Form eines Strings. Das ist fehleranfällg, weil die Klasse und die Methode erst zur Laufzeit -- also bei der Test-Ausführung -- auf Existenz geprüft werden.
Man kann das mitigieren, indem man den String in eine Konstante auslagert:
private static final String TEST_DATA = "org.mletkin.unittest.TestDaten#pwdWirdNichtAkzeptiert"; ... @MethodSource(TEST_DATA)
Das eröffnet zum einen die Möglichkeit Test-Methoden zentral bereitzustellen und zum anderen die Möglichkeit die Strings auf Gültigkeit zu überprüfen. Das geschieht dann zwar auch erst zur Laufzeit, der Fehler tritt dann aber wenigstens da auf wo er geschehen ist.
Variante 3: die Testdaten-Provider-Klasse
Eine weitere Möglichkeit den Testdaten-Provider zu implementieren ist die Definition in einer eigenen Klasse. Eine solche Klasse kann allerdings nur eine einzige Testdaten-Methode anbieten, da der Zugriff über ein Interface erfolgt:
public class UngueltigePassworte implements ArgumentsProvider { @Override public Stream<Arguments> provideArguments(ExtensionContext context) { return Stream.of( Arguments.of("Hallo", "nur Buchstaben"), Arguments.of("1234567", "nur Ziffern"), Arguments.of("!%#&/()", "nur Sonderzeichen") ); } }
Die Testdaten-Provider-Klasse muß das Interface ArgumentsProvider
implementieren und dazu die oben gezeigte Methode
implementierten. Sie erhält als Argument ein Kontext-Objekt das Informationen zur Umgebung der Test-Ausführung enthält.
In unserem Beispiel machen wir keinen Gebrauch davon.
Die Verwendung erfolgt über die Annotation @ArgumentsSource
, der jetzt die Testdaten-Provider-Klasse in Form eines
Class
-Objekts übergeben wird:
@ArgumentSource(UngueltigePassworte .class)
Im Gegensatz zur @MethodSource
-Verwendung in den vorangegangenen Varianten wird hier schon zur Compile-Zeit sichergestellt
daß die Testdaten-Provider-Klasse und die -Methode existieren.