In JUnit 4 war es leicht zu Test Invarianten über eine Reihe von Klassen durch die Verwendung der @Parameterized
Annotation. Der Schlüssel ist , dass eine Sammlung von Tests gegen eine einzige Liste von Argumenten ausgeführt werden.
Wie dies in JUnit 5 replizieren, ohne JUnit-Jahrgang mit?
@ParameterizedTest
ist zu einer Testklasse nicht anwendbar. @TestTemplate
klang wie es sinnvoll sein könnte, aber das Annotation des Ziel ist auch ein Verfahren.
Ein Beispiel eines solchen JUnit 4 Test ist:
@RunWith( Parameterized.class )
public class FooInvariantsTest{
@Parameterized.Parameters
public static Collection<Object[]> data(){
return new Arrays.asList(
new Object[]{ new CsvFoo() ),
new Object[]{ new SqlFoo() ),
new Object[]{ new XmlFoo() ),
);
}
private Foo fooUnderTest;
public FooInvariantsTest( Foo fooToTest ){
fooUnderTest = fooToTest;
}
@Test
public void testInvariant1(){
...
}
@Test
public void testInvariant2(){
...
}
}
Die parametrisierte Testfunktion in JUnit 5 bietet nicht exakt die gleichen Funktionen als die von JUnit 4 vorgesehen
Neue Funktionen mit mehr Flexibilität eingeführt wurden ... aber es auch die JUnit4 Funktion , wo die parametrisierte Testklasse verwendet die parametrisierte Stände / Behauptungen verloren auf Klassenebene , die für alle Prüfmethoden der Klasse ist.
Definieren @ParameterizedTest
für jedes Testverfahren durch die „Eingabe“ spezifiziert wird , so benötigt.
Darüber hinaus fehlt ich werde die wichtigsten Unterschiede zwischen den zwei Versionen präsentieren und wie 5 in JUnit parametrisierte Tests zu verwenden.
TL; DR
Um einen parametrisierte Test zu schreiben, der einen Wert von Fall zu testen , wie Ihre in Ihrer Frage gibt, org.junit.jupiter.params.provider.MethodSource
soll die Arbeit machen.
@MethodSource
können Sie eine oder mehrere Methoden der Testklasse verweisen. Jede Methode muss wieder einStream
,Iterable
,Iterator
, oder ein Array von Argumenten. Darüber hinaus muss jede Methode keine Argumente akzeptieren. Standardmäßig müssen solche Methoden statisch sein , wenn die Testklasse wird mit Anmerkungen versehen mit@TestInstance(Lifecycle.PER_CLASS)
.Wenn Sie nur einen einzigen Parameter benötigen, können Sie Instanzen des Parameters Typ zurückgeben direkt wie das folgende Beispiel demonstriert.
Wie JUnit 4, @MethodSource
beruht auf einem Fabrikmethode als auch für Testverfahren verwendet werden kann , die mehrere Argumente angeben.
In JUnit 5 ist es die Art und Weise parametriert Tests des Schreibens in der Nähe von JUnit 4.
JUnit 4:
@Parameters
public static Collection<Object[]> data() {
JUnit 5:
private static Stream<Arguments> data() {
Die wichtigsten Verbesserungen:
Collection<Object[]>
geworden ist , Stream<Arguments>
dass mehr Flexibilität bietet.
die Möglichkeit , die Factory - Methode der Testmethode der Bindung unterscheidet sich ein wenig.
Es ist jetzt kürzer und weniger fehleranfällig: nicht mehr Anforderung einen Konstruktor zu erstellen und erklärt Feld den Wert der einzelnen Parameter einzustellen. Die Bindung der Quelle erfolgt direkt auf die Parameter des Testverfahrens.
Mit JUnit 4, in einer gleichen Klasse, ein und nur ein Factory - Methode muss mit erklärt @Parameters
.
Mit JUnit 5 wird diese Einschränkung aufgehoben: mehrere Methoden in der Tat als Factory - Methode verwendet werden.
Also, in der Klasse, können wir so einige Testmethoden mit kommentierten erklären , @MethodSource("..")
dass siehe Methoden unterschiedliche Fabrik.
Zum Beispiel ist hier eine Probe-Test-Klasse, die einige zusätzlich Berechnungen behauptet:
import java.util.stream.Stream;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.junit.jupiter.api.Assertions;
public class ParameterizedMethodSourceWithArgumentsTest {
@ParameterizedTest
@MethodSource("addFixture")
void add(int a, int b, int result) {
Assertions.assertEquals(result, a + b);
}
private static Stream<Arguments> addFixture() {
return Stream.of(
Arguments.of(1, 2, 3),
Arguments.of(4, -4, 0),
Arguments.of(-3, -3, -6));
}
}
Um ein Upgrade bestehende parametrisiert Tests von JUnit 4 bis JUnit 5, @MethodSource
ist ein Kandidat zu betrachten.
Zusammenfassen
@MethodSource
einige Stärken hat aber auch einige Schwächen.
Neue Wege Quellen der parametrisierte Tests wurden eingeführt in JUnit 5. angeben
Hier einige zusätzliche Informationen (weit abschließend ist) über ihnen , dass ich hoffe , eine große Idee, wie viel mit in allgemeiner Art und Weise geben könnte.
Einführung
JUnit 5 führt parametrisiert Tests verfügen in diesen Begriffen:
Parameterized Tests machen es möglich , einen Test mehrmals mit verschiedenen Argumenten zu laufen. Sie werden wie normale erklärt
@Test
Methoden , sondern verwenden Sie die@ParameterizedTest
Anmerkung statt. Darüber hinaus müssen Sie mindestens eine Quelle angeben, die die Argumente für jeden Aufruf zur Verfügung stellen.
Dependency Anforderung
Parameterized Tests Funktion ist in der nicht enthält junit-jupiter-engine
Kern Abhängigkeit.
Sie sollten eine spezifische Abhängigkeit hinzufügen , es zu benutzen: junit-jupiter-params
.
Wenn Sie Maven verwenden, ist dies die Abhängigkeit zu erklären:
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<version>5.0.0</version>
<scope>test</scope>
</dependency>
Quellen zur Verfügung, um Daten zu erstellen
Im Gegensatz zu JUnit 4, JUnit 5 bietet mehrere Aromen und Artefakte zu parametrieren Tests schreiben
die Wege zu Gunsten hängen in der Regel von der Quelle der Daten , die Sie verwenden möchten.
Hier sind die Quellentypen von Rahmen vorgeschlagen und in der beschriebenen Dokumentation :
@ValueSource
@EnumSource
@MethodSource
@CsvSource
@CsvFileSource
@ArgumentsSource
Hier sind die 3 wichtigsten Quellen, die ich eigentlich mit JUnit verwenden 5 und ich präsentieren:
@MethodSource
@ValueSource
@CsvSource
Ich betrachte sie als Grund wie ich parametrisierte Tests schreiben. Sie sollten in JUnit 5, die Art von 4 Tests JUnit schreiben lassen , dass Sie beschrieben.
@EnumSource
, @ArgumentsSource
Und @CsvFileSource
seine natürlich hilfreich sein , aber sie sind mehr spezialisiert.
Präsentation @MethodSource
, @ValueSource
und@CsvSource
1) @MethodSource
Diese Art der Quelle erfordert eine Factory - Methode zu definieren.
Aber es gibt auch viel Flexibilität.
In JUnit 5 ist es die Art und Weise parametriert Tests des Schreibens in der Nähe von JUnit 4.
Wenn Sie einen haben einzelne Methode Parameter in der Testmethode und die Sie verwenden möchten , jede Art als Quelle, @MethodSource
ist ein sehr guter Kandidat.
Um dies zu erreichen, definiert ein Verfahren , welches Returns einen Strom von dem Wert für jeden Fall und mit Anmerkungen versehen , die Testmethode mit @MethodSource("methodName")
dem methodName
ist der Name dieser Datenquelle Methode.
Zum Beispiel könnten Sie schreiben:
import java.util.stream.Stream;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
public class ParameterizedMethodSourceTest {
@ParameterizedTest
@MethodSource("getValue_is_never_null_fixture")
void getValue_is_never_null(Foo foo) {
Assertions.assertNotNull(foo.getValue());
}
private static Stream<Foo> getValue_is_never_null_fixture() {
return Stream.of(new CsvFoo(), new SqlFoo(), new XmlFoo());
}
}
Wenn Sie mehrere Verfahrensparameter in der Testmethode und die Sie verwenden möchten , jede Art als Quelle, @MethodSource
ist auch ein sehr guter Kandidat.
Um dies zu erreichen, definiert ein Verfahren , das einen Strom von kehrt org.junit.jupiter.params.provider.Arguments
für jeden Fall zu prüfen.
Zum Beispiel könnten Sie schreiben:
import java.util.stream.Stream;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.junit.jupiter.api.Assertions;
public class ParameterizedMethodSourceWithArgumentsTest {
@ParameterizedTest
@MethodSource("getFormatFixture")
void getFormat(Foo foo, String extension) {
Assertions.assertEquals(extension, foo.getExtension());
}
private static Stream<Arguments> getFormatFixture() {
return Stream.of(
Arguments.of(new SqlFoo(), ".sql"),
Arguments.of(new CsvFoo(), ".csv"),
Arguments.of(new XmlFoo(), ".xml"));
}
}
2)@ValueSource
Wenn Sie einen haben einzelne Methode Parameter in der Testmethode und Sie können die Quelle des Parameters von repräsentieren eine dieser integrierten Typen (String, int, long, double) , @ValueSource
Anzüge.
@ValueSource
definiert, in der Tat diese Attribute:
String[] strings() default {};
int[] ints() default {};
long[] longs() default {};
double[] doubles() default {};
Sie könnten zum Beispiel auf diese Weise verwenden:
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
public class ParameterizedValueSourceTest {
@ParameterizedTest
@ValueSource(ints = { 1, 2, 3 })
void sillyTestWithValueSource(int argument) {
Assertions.assertNotNull(argument);
}
}
Beware 1) nicht mehr als eine Anmerkung Attribut angeben müssen.
Vorsicht vor 2) die Zuordnung zwischen der Quelle und dem Parameter des Verfahrens kann zwischen zwei verschiedenen Arten erfolgen.
Die Art String
als Datenquelle verwendet wird, erlaubt besonders dank seiner Analyse, in mehrere andere Typen umgewandelt werden.
3) @CsvSource
Wenn Sie mehrere Verfahrensparameter in dem Testverfahren, ein @CsvSource
Anzug kann.
Um sie zu verwenden, den Test mit Anmerkungen versehen @CsvSource
und in einem Array von spezifizieren String
jeweils.
Werte von jeweils durch ein Komma getrennt.
Wie @ValueSource
ich die Abbildung zwischen der Quelle und dem Parameter des Verfahrens kann zwischen zwei verschiedenen Arten erfolgen.
Hier ist ein Beispiel, das veranschaulicht:
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
public class ParameterizedCsvSourceTest {
@ParameterizedTest
@CsvSource({ "12,3,4", "12,2,6" })
public void divideTest(int n, int d, int q) {
Assertions.assertEquals(q, n / d);
}
}
@CsvSource
VS @MethodSource
Diese Quellentypen dienen eine sehr klassische Anforderung: Abbilden von der Quelle zu mehreren Verfahrensparametern in der Testmethode.
Aber ihr Ansatz ist anders.
@CsvSource
hat einige Vorteile: es klarer und kürzer ist.
Tatsächlich sind Parameter definiert knapp über der getestete Methode, keine Anforderung einer Befestigung Methode zu erstellen , die Warnungen zusätzlich generieren „ungenutzt“ kann.
Aber es hat auch eine wichtige Einschränkung Mapping - Arten betreffen.
Sie haben eine Reihe von zur Verfügung zu stellen String
. Das Framework bietet Konvertierungsfunktionen , aber es ist begrenzt.
Zusammenfassend , während die String
als Quelle zur Verfügung gestellt und die Parameter des Testverfahrens haben den gleichen Typ ( String
-> String
) oder sich auf integrierte Umwandlung in ( String
-> int
zum Beispiel), @CsvSource
wird als die Weise zu nutzen.
Da es nicht der Fall ist, müssen Sie zwischen Beibehaltung der Flexibilität des eine Wahl treffen , @CsvSource
indem Sie einen benutzerdefinierten Wandler ( ArgumentConverter
Unterklasse) für Konvertierungen nicht durchgeführt durch den Rahmen oder unter Verwendung von @MethodSource
mit einer Factory - Methode , dass die Renditen Stream<Arguments>
.
Es hat die beschriebenen Nachteile oben , aber es hat auch den großen Vorteil abzubilden out-of-the - Box jede Art von der Quelle auf die Parameter.
Argument Conversion
Über die Zuordnung zwischen der Quelle ( @CsvSource
oder @ValueSource
zum Beispiel) und die Parameter des Testverfahrens, wie es zu sehen ist , kann der Rahmen einige Umwandlungen tun , wenn die Typen nicht übereinstimmen.
Hier ist eine Präsentation der zwei Arten von Umwandlungen:
3.13.3. Argument Conversion
implizite Konvertierung
Um Anwendungsfälle wie zu unterstützen
@CsvSource
, JUnit Jupiter bietet eine Reihe von integrierten in impliziten Typ - Wandler. Der Umwandlungsprozess hängt von dem deklarierten Typ jeden Verfahrensparameters......
String
Instanzen derzeit auf die folgenden Zieltypen implizit konvertiert.Target Type | Example boolean/Boolean | "true" → true byte/Byte | "1" → (byte) 1 char/Character | "o" → 'o' short/Short | "1" → (short) 1 int/Integer | "1" → 1 .....
Zum Beispiel in dem vorherigen Beispiel wird eine implizite Konvertierung zwischen getan String
von der Quelle und int
als Parameter definiert ist :
@CsvSource({ "12,3,4", "12,2,6" })
public void divideTest(int n, int d, int q) {
Assertions.assertEquals(q, n / d);
}
Und hier ist eine implizite Konvertierung von getan String
Quelle LocalDate
Parameter:
@ParameterizedTest
@ValueSource(strings = { "2018-01-01", "2018-02-01", "2018-03-01" })
void testWithValueSource(LocalDate date) {
Assertions.assertTrue(date.getYear() == 2018);
}
Wenn für zwei Typen, keine Konvertierung von Rahmen vorgesehen ist, die der Fall für benutzerdefinierte Typen ist, sollten Sie eine verwenden ArgumentConverter
.
explizite Konvertierung
Stattdessen implizites Argument Umwandlung verwenden , können Sie explizit eine angeben
ArgumentConverter
für einen bestimmten Parameter verwenden , um die Verwendung von@ConvertWith
Annotations wie im folgende Beispiel.
JUnit bietet eine Referenzimplementierung für Kunden , die eine bestimmte erstellen müssen ArgumentConverter
.
Explizite Argument Wandler sollen durch Test Autoren umgesetzt werden. So junit-jupiter-params liefert nur einen einzigen expliziten Argument Konverter, der auch als Referenz - Implementierung dienen können:
JavaTimeArgumentConverter
. Sie wird über die zusammengesetzte Anmerkung verwendetJavaTimeConversionPattern
.
Testverfahren unter Verwendung dieser Konverter:
@ParameterizedTest
@ValueSource(strings = { "01.01.2017", "31.12.2017" })
void testWithExplicitJavaTimeConverter(@JavaTimeConversionPattern("dd.MM.yyyy") LocalDate argument) {
assertEquals(2017, argument.getYear());
}
JavaTimeArgumentConverter
Konverterklasse:
package org.junit.jupiter.params.converter;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.OffsetDateTime;
import java.time.OffsetTime;
import java.time.Year;
import java.time.YearMonth;
import java.time.ZonedDateTime;
import java.time.chrono.ChronoLocalDate;
import java.time.chrono.ChronoLocalDateTime;
import java.time.chrono.ChronoZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalQuery;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import org.junit.jupiter.params.support.AnnotationConsumer;
/**
* @since 5.0
*/
class JavaTimeArgumentConverter extends SimpleArgumentConverter
implements AnnotationConsumer<JavaTimeConversionPattern> {
private static final Map<Class<?>, TemporalQuery<?>> TEMPORAL_QUERIES;
static {
Map<Class<?>, TemporalQuery<?>> queries = new LinkedHashMap<>();
queries.put(ChronoLocalDate.class, ChronoLocalDate::from);
queries.put(ChronoLocalDateTime.class, ChronoLocalDateTime::from);
queries.put(ChronoZonedDateTime.class, ChronoZonedDateTime::from);
queries.put(LocalDate.class, LocalDate::from);
queries.put(LocalDateTime.class, LocalDateTime::from);
queries.put(LocalTime.class, LocalTime::from);
queries.put(OffsetDateTime.class, OffsetDateTime::from);
queries.put(OffsetTime.class, OffsetTime::from);
queries.put(Year.class, Year::from);
queries.put(YearMonth.class, YearMonth::from);
queries.put(ZonedDateTime.class, ZonedDateTime::from);
TEMPORAL_QUERIES = Collections.unmodifiableMap(queries);
}
private String pattern;
@Override
public void accept(JavaTimeConversionPattern annotation) {
pattern = annotation.value();
}
@Override
public Object convert(Object input, Class<?> targetClass) throws ArgumentConversionException {
if (!TEMPORAL_QUERIES.containsKey(targetClass)) {
throw new ArgumentConversionException("Cannot convert to " + targetClass.getName() + ": " + input);
}
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
TemporalQuery<?> temporalQuery = TEMPORAL_QUERIES.get(targetClass);
return formatter.parse(input.toString(), temporalQuery);
}
}
Dieser Artikel stammt aus dem Internet. Bitte geben Sie beim Nachdruck die Quelle an.
Bei Verstößen wenden Sie sich bitte [email protected] Löschen.
Lass mich ein paar Worte sagen