[JAVA] Änderungen in JUnit5M4-> M5

Dies ist meine erste Qiita.

Taste of JUnit 5 auf der KANJAVA PARTY 2017 !!! am 24. Juni 2017 / junit5falsewei-jian) wurde unter dem Titel angekündigt. Die Version zum Zeitpunkt der Ankündigung war M4, aber es gibt einige Änderungen in M5, also werde ich Ihnen folgen.

Da wir hier jedoch hauptsächlich JUnit Jupiter beschreiben, finden Sie weitere Informationen im Original JUnit5 User Guide. Bitte nehmen Sie Bezug darauf.

Alle JAR-Dateien haben ein Manifest-Attribut namens "Automatic-Module-Name" erhalten.

Es ist kompatibel mit Jigsaw. Jigsaw ist damit nicht sehr vertraut, deshalb werde ich es vermeiden.

Der Parameter "@ ParameterizedTest" gilt jetzt nur für Testmethoden

Es ist ein bisschen verwirrend. Schreiben Sie den Code. In JUnit5M4 versuche ich, den Parameter @ ParameterrizedTest anzuwenden, da zum Zeitpunkt des Methodenrückrufs von setup1 ein Argument vorhanden ist. Dies schlägt jedoch fehl, da die Typen nicht übereinstimmen. Stattdessen konnte ich die Parameter von ParameterizedTest mit der Lifecycle-Callback-Methode wie setup2 empfangen. In JUnit5M5 wird der Parameter von "@ ParameterizedTest" nicht mehr auf die Rückrufmethode für den Lebenszyklus angewendet, sodass beim Rückruf von setup2 ein Fehler auftritt. Dieser Fix soll seltsame Probleme vermeiden, wenn "@ ParameterizedTest" und "normaler" @ Test "in einer Testklasse gemischt werden.

ParameterizedNGTest.java


public class ParameterizedNGTest {
	@BeforeEach
	void setUp1(TestInfo info) {
	}

	@BeforeEach
	void setUp2(String p1, String p2) {
		System.out.println(p1 + p2);
	}
	
	@ParameterizedTest
	@CsvSource({ "x, 1", "y, 2","z, 3" })
	void testIt(String input, String expected) {
	}
}

Der Artefaktname "junit-jupiter-migrationsunterstützung" wurde in "junit-jupiter-migrationsupport" geändert.

Bitte seien Sie vorsichtig, wenn Sie mit Maven oder Gradle erwerben.

Die folgenden APIs haben sich geändert

Wenn sich die Klasse nicht ändert, wird der Klassenname weggelassen.

Alte API Neue API Bemerkungen
ParameterResolver#supports() supportsParameter()
ParameterResolver#resolve() resolveParameter()
ContainerExecutionCondition#evaluate() ExecutionCondition#evaluateExecutionCondition() ContainerExecutionCondition wird aufgehoben
TestExecutionCondition#evaluate() ExecutionCondition#evaluateExecutionCondition() TestExecutionCondition wird aufgehoben
TestExtensionContext#getTestException() ExtensionContext#getExecutionException() TestExtensionContext wird abgeschafft
TestExtensionContext#getTestInstance() ExtensionContext#getTestInstance() TestExtensionContext wird abgeschafft. Der Rückgabewert ist ebenfalls Object-> Optional<Object>Ändern
TestTemplateInvocationContextProvider#supports() supportsTestTemplate()
TestTemplateInvocationContextProvider#resolve() provideTestTemplateInvocationContexts()
ArgumentsProvider#arguments() provideArguments()
ObjectArrayArguments#create() Arguments#of() ObjectArrayArguments veraltet
@MethodSource#names value

Einführung von "@ TestInstance"

Die Annotation "@ TestInstance" ist eine Annotation, die den Lebenszyklus einer Testklasse steuert. Bisher hat JUnit bei jeder Ausführung einer Testmethode eine Testklasse eingerichtet.

TestInstancePerMethodTest.java


@RunWith(JUnitPlatform.class)
public class TestInstancePerMethodTest {
	private int i = 0;
	
	@Test
	void test1(){System.out.println(i++);}
	@Test
	void test2(){System.out.println(i++);}
}

Ausführungsergebnis.


0
0

Wenn Sie "@ TestInstance" angeben (und Lifecycle.PER_CLASS angeben), wird die Testklasse nur einmal materialisiert und das Ergebnis ist unterschiedlich.

TestInstancePerClassTest.java


@RunWith(JUnitPlatform.class)
@TestInstance(Lifecycle.PER_CLASS)
public class TestInstancePerClassTest {
	private int i = 0;
	
	@Test
	void test1(){System.out.println(i++);}
	@Test
	void test2(){System.out.println(i++);}
}

Ausführungsergebnis.


0
1

Durch das Gewähren von "@ TestInstance" werden die Ausführungskosten der Testklasse reduziert. Beachten Sie jedoch, dass der Initialisierungsprozess in "@ BeforeEach" und nicht zum Zeitpunkt der Initialisierung durchgeführt werden muss.

Gleichzeitig sollte beachtet werden, dass "@ BeforeAll" und "@ AfterAll" so angegeben werden müssen, dass sie der Materialisierung der Testklasse entsprechen, was die Geschichte etwas kompliziert macht.

Mit anderen Worten, im Fall der Angabe von PER_CLASS tritt ein Laufzeitfehler auf, es sei denn, "@ BeforeAll" oder "@ AfterAll" wird für die dynamische Methode anstelle der statischen Methode mit Anmerkungen versehen.

Wenn Sie "@ TestInstance" und "@ Nested" zusammen verwenden, können Sie "@ BeforeAll" und "@ AfterAll" auch für verschachtelte Testklassen schreiben. Daher ist es möglicherweise besser, sie ordnungsgemäß zu verwenden. Es kann sein.

Wenn Sie "@ TestInstance" verwenden, ändert sich übrigens die Reihenfolge der Lebenszyklus-Rückrufe. CallBackOrderTest.java Das Ausgabeergebnis, wenn es so ausgeführt wird, wie es ist, ist wie in ① gezeigt, aber wenn @ TestInstance mit Anmerkungen versehen ist, ist es wie in ② gezeigt. Ich denke, es ist ein Ärger, aber wenn Sie normal darüber nachdenken, ist das das Ergebnis.

①.


ExecutionCondition:false
beforeAll
postProcessTestInstance
ExecutionCondition:true
beforeEach
beforeTestExecution
foo
handleTestExecutionException
afterTestExecution
afterEach
afterAll

②.


postProcessTestInstance
ExecutionCondition:false
beforeAll
ExecutionCondition:true
beforeEach
beforeTestExecution
foo
handleTestExecutionException
afterTestExecution
afterEach
afterAll

Die Spezifikation von assertAll hat sich geändert

Bis JUnit5M4 wurden die nachfolgenden ausführbaren Dateien nicht ausgewertet und der Test als Fehler behandelt, wenn in jeder ausführbaren Datei ohne assertAll eine Ausnahme auftrat. Nach M5 traten jedoch andere Ausnahmen als Ausnahmen auf der schwarzen Liste auf. Die Auswertung wird aber nicht mehr unterbrochen. Die Ausführungsergebnisse von M4 und M5, wenn der folgende Code vorhanden ist, sind unten gezeigt.

AssertAllInExceptionTest.java


@RunWith(JUnitPlatform.class)
public class AssertAllInExceptionTest {
	@Test
	void thrownNullPointerException() {
		assertAll(
				() -> {throw new NullPointerException();},
				() -> assertEquals(2, 3)
		);
	}
}
Ausführungsergebnis von M4 Ausführungsergebnis von M5
Screenshot 2017-07-13 13.09.51.png Screenshot 2017-07-13 13.14.23.png

Sie können sehen, dass M4 als Fehler, M5 als Fehler und die zweite ausführbare Datei ausgewertet wird.

Später habe ich das Wort "Blacklist Exception" früher verwendet, aber es gibt eine Frage, die besagt "das ist was es ist!". Im Benutzerhandbuch wurde das Wort "Ausnahme auf der schwarzen Liste" im Teil der Ankündigung der Spezifikationsänderung von assertAll und eine Stelle später im Release Note von M2 erwähnt.

If the exception is a blacklisted exception such as an OutOfMemoryError, however, it will be rethrown.

Die Antwort auf die Frage "Was ist wie (usw.) !! Was gibt es sonst noch !!" war nicht im Benutzerhandbuch, sondern im Code.

[BlacklistedExceptions.java](https://github.com/junit-team/junit5/blob/r5.0.0-M4/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ Soweit ich den Code BlacklistedExceptions.java sehen kann, scheint es sich derzeit nur um OutOfMemoryError zu handeln.

@ TestTemplate wurde geschrieben

Es scheint, dass es von JUnit5M4 war, aber ich habe es übersehen, weil es nicht im Benutzerhandbuch geschrieben wurde. Es gab eine Beschreibung im Benutzerhandbuch von JUnit5M5, daher werde ich hier eine Übersicht schreiben.

Ich denke, dass "@ TestTemplate", wie "@ ParameterizedTest", zum Trennen von Testcode und Testdaten dient. Ich habe den Code gelesen und festgestellt, dass "@ ParameterizedTest" eine Annotation ist, die "@ TestTemplate" kommentiert. Daher denke ich, dass "@ TestTemplate" kein Problem sein sollte, wenn Sie mit "@ ParameterizedTest" nicht unzufrieden sind. Ich werde.

Das Folgende ist eine leicht modifizierte Version der maschinellen Übersetzung des Benutzerhandbuchs.

3.14. Test Templates

Die @ TestTemplate -Methode ist eine Vorlage für Testfälle, nicht für reguläre Testfälle. Daher kann es abhängig von der Anzahl der vom registrierten Anbieter zurückgegebenen Anrufkontexte mehrmals aufgerufen werden. Daher sollte "@ TestTemplate" in Verbindung mit einer Erweiterung verwendet werden, die TestTemplateInvocationContextProvider implementiert. Das Aufrufen einer Testvorlagenmethode verhält sich wie eine normale Ausführung der @ Test-Methode und unterstützt dieselben Lebenszyklus-Rückrufe und -Erweiterungen vollständig. Anwendungsbeispiele finden Sie unter Bereitstellen von Aufrufkontexten für Testvorlagen.

5.8. Providing Invocation Contexts for Test Templates

Die @ TestTemplate-Methode kann nur ausgeführt werden, wenn mindestens ein TestTemplateInvocationContextProvider registriert ist. Jeder dieser Anbieter stellt einen Stream von TestTemplateInvocationContext-Instanzen bereit. Jeder Kontext kann einen benutzerdefinierten Anzeigenamen und eine Liste zusätzlicher Erweiterungen angeben, die nur beim nächsten Aufruf der Methode "@ TestTemplate" verwendet werden sollen. Das folgende Beispiel beschreibt eine Testvorlage und zeigt, wie ein TestTemplateInvocationContextProvider registriert und implementiert wird.

@TestTemplate
@ExtendWith(MyTestTemplateInvocationContextProvider.class)
void testTemplate(String parameter) {
    assertEquals(3, parameter.length());
}

static class MyTestTemplateInvocationContextProvider implements TestTemplateInvocationContextProvider {
    @Override
    public boolean supportsTestTemplate(ExtensionContext context) {
        return true;
    }

    @Override
    public Stream<TestTemplateInvocationContext> provideTestTemplateInvocationContexts(ExtensionContext context) {
        return Stream.of(invocationContext("foo"), invocationContext("bar"));
    }

    private TestTemplateInvocationContext invocationContext(String parameter) {
        return new TestTemplateInvocationContext() {
            @Override
            public String getDisplayName(int invocationIndex) {
                return parameter;
            }

            @Override
            public List<Extension> getAdditionalExtensions() {
                return Collections.singletonList(new ParameterResolver() {
                    @Override
                    public boolean supportsParameter(ParameterContext parameterContext,
                            ExtensionContext extensionContext) {
                        return parameterContext.getParameter().getType().equals(String.class);
                    }

                    @Override
                    public Object resolveParameter(ParameterContext parameterContext,
                            ExtensionContext extensionContext) {
                        return parameter;
                    }
                });
            }
        };
    }
}

In diesem Beispiel wird die Testvorlage zweimal aufgerufen. Der Anzeigename des Anrufs lautet "foo" und "bar" und wird im Anrufkontext angegeben. Jeder Aufruf registriert einen benutzerdefinierten ParameterResolver, mit dem die Methodenparameter aufgelöst werden. Die Ausgabe bei Verwendung von ConsoleLauncher lautet:

└─ testTemplate(String) ✔
   ├─ foo ✔
   └─ bar ✔

Mit der Erweiterungs-API TestTemplateInvocationContextProvider können Sie in erster Linie Testklasseninstanzen separat mit unterschiedlichen Kontexten vorbereiten, z. B. unterschiedlichen Parametern, oder mehrere Male erstellen, ohne den Kontext zu ändern. Tests in - Wird hauptsächlich verwendet, um verschiedene Tests zu implementieren, die auf wiederholten Aufrufen ähnlicher Methoden beruhen.

Vom Menschen lesbarer Anzeigename, wenn @ ParameterizedTest ein Array als Argument akzeptiert

Wahrscheinlich als Antwort auf dieses Problem, wenn Sie versuchen, einfach ein Array-Objekt in Java auszugeben, [Ljava.lang.String; @ 7c29daf3 Ich glaube, ich habe die Tatsache behoben, dass ich den Inhalt nicht sehen konnte.

Ich konnte es jedoch nicht überprüfen, da ich keinen kleinen Code schreiben konnte, der zwischen M4 und M5 verglichen werden kann. Entschuldigung.

Die Spezifikation von "@ EnumSource" wurde geändert

In M4 gaben die Namen von "@ EnumSource" den zu erfassenden Enum-Namen an, aber durch Hinzufügen der Eigenschaft "mode" in M5 kann die Bedeutung der an Namen übergebenen Informationen geändert werden. Es war.

Mode Bedeutung von Namen
INCLUDE Standardwert. Gilt nur für den in Namen angegebenen Enum-Namen
EXCLUDE Gilt nur für Enum-Namen, die nicht in Namen angegeben sind
MATCH_ALL Gilt nur für Enum-Namen, die mit allen in Namen angegebenen regulären Ausdrücken übereinstimmen
MATCH_ANY Gilt nur für Enum-Namen, die mit den in Namen angegebenen regulären Ausdrücken übereinstimmen

(Solo) Ich möchte es nicht so oft benutzen w

Die Spezifikation von "@ MethodSource" wurde geändert

Die Angabe von DoubleStream, IntStream oder LongStream als Rückgabewert der von @ MethodSource angegebenen Methode verursacht keinen Fehler mehr.

Die Spezifikation von "@ TestFactory" hat sich geändert

@ TestFactory unterstützt jetzt jeden verschachtelten dynamischen Container. Weitere Informationen finden Sie unter Dynamic Container und im abstrakten DynamicNode. Siehe junit5 / docs / current / api / org / junit / jupiter / api / DynamicNode.html).

Es ist das. Ein Beispiel ist auch dem Benutzerhandbuch beigefügt.

    @TestFactory
    Stream<DynamicNode> dynamicTestsWithContainers() {
        return Stream.of("A", "B", "C")
            .map(input -> dynamicContainer("Container " + input, Stream.of(
                dynamicTest("not null", () -> assertNotNull(input)),
                dynamicContainer("properties", Stream.of(
                    dynamicTest("length > 0", () -> assertTrue(input.length() > 0)),
                    dynamicTest("not empty", () -> assertFalse(input.isEmpty()))
                ))
            )));
    }

Als ich mir das ansah, konnte ich irgendwie sehen, wie man Dynamic Test einsetzt. Ist DynamicTest ein Mechanismus, der es einfach macht, von einem externen DSL geschriebene Tests in einen strukturierten Satz von Testcode zu übersetzen, damit er ordnungsgemäß gemeldet werden kann?

Die AfterAllCallback-Implementierungsschnittstelle kann jetzt Ausnahmen abfangen, die von "@ BeforeAll" ausgelöst wurden.

Genau genommen scheint es eine Ausnahme zu sein, die in der Methode aufgetreten ist, die "@ BeforeAll" oder die Implementierungsmethode der BeforeAllCallback-Schnittstelle kommentiert hat.

Ich war mir dessen nicht bewusst, aber es bedeutet, dass ich es mit M4 nicht machen konnte. Ich habe nachgeschlagen, aber in M4 war das Argument für AfterAllCallback # afterAll ContainerExtensionContext, und es gab keine API, um die aufgetretene Ausnahme abzurufen. Ab M5 wurde ContainerExtensionContext in ExtensionContedxt integriert, sodass es erfasst werden kann.

In derselben Theorie können Ausnahmen, die bei "@ BeforeEach" ausgelöst werden, von der AfterEachCallback-Implementierungsschnittstelle abgefangen werden. (Erhältlich bei M4)

Informationen können jetzt über den Store zwischen Testklassen ausgetauscht werden

Ja, ich bin mir nicht sicher.

Extensions may now share state across top-level test classes by using the Store of the newly introduced engine-level ExtensionContext.

Es gibt jedoch zu wenige Erklärungen zum Store ...

API-Reife

Nur diejenigen, die sich vom Zeitpunkt des M4-Dokuments unterscheiden / neu sind, aber wie folgt.

Alte Reife Neue Reife
@TestInstance - Unbeschrieben
@TestTemplate - Experimental
Assertions#assertAll Maintained Experimental
Assumptions#assumingThat Maintained Experimental
DynamicContainer - Experimental
DynamicNode - Experimental
ExecutionCondition - Experimental
TestTemplateInvocationContextProvider - Experimental
TestTemplateInvocationContext - Experimental

Grundsätzlich gibt es nur Auslassungen oder Ergänzungen, die sich möglicherweise nicht für jeden Meilenstein ändern.

Ist es so

In den Versionshinweisen des Benutzerhandbuchs sind die wichtigsten Änderungen außer Kapitel 7 wie folgt.

Schließlich

Ich hatte in letzter Zeit nicht viele Möglichkeiten, dies bekannt zu geben, daher werde ich mein Bestes für JUnit 5 geben. Wir hoffen, Sie zumindest bis zur offiziellen Veröffentlichung über die Änderungen auf dem Laufenden zu halten.

Der nächste Meilenstein ist M6, aber ab dem 14. Juli 2017 soll er am 16. Juli 2017 veröffentlicht werden, und der Fortschritt scheint 42% zu betragen, sodass er sich wahrscheinlich verzögern wird

Recommended Posts

Änderungen in JUnit5M4-> M5
Änderungen in Mockito 2
Änderungen in mybatis-spring-boot-Starter 2.0
Änderungen im Mybatis-Spring-Boot-Starter 2.1
Änderungen im Mybatis-Spring-Boot-Starter 1.3
Änderungen im Mybatis-Spring-Boot-Starter 1.2
Änderungen des Kernstandorts in iOS 14
Wichtige Änderungen in Spring Boot 1.5
Wichtige Änderungen in der Kernfunktionalität von Spring Framework 5.0