From 3105d1b3fc00ba4d2a83620602ea8ce92ad9e6e6 Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Mon, 21 Oct 2024 14:55:54 +0200 Subject: [PATCH] Allow repeating `ExtendWith` annotation on fields and parameters Fixes #4059. --- .../release-notes/release-notes-5.11.3.adoc | 3 +- .../jupiter/api/extension/Extensions.java | 2 +- ...gistrationViaParametersAndFieldsTests.java | 41 ++++++++++++++++--- .../tooling/support/tests/ArchUnitTests.java | 3 -- 4 files changed, 39 insertions(+), 10 deletions(-) diff --git a/documentation/src/docs/asciidoc/release-notes/release-notes-5.11.3.adoc b/documentation/src/docs/asciidoc/release-notes/release-notes-5.11.3.adoc index 55fcc69e76fd..d364b73b4739 100644 --- a/documentation/src/docs/asciidoc/release-notes/release-notes-5.11.3.adoc +++ b/documentation/src/docs/asciidoc/release-notes/release-notes-5.11.3.adoc @@ -38,10 +38,11 @@ on GitHub. * Extensions can once again be registered via multiple `@ExtendWith` meta-annotations on the same composed annotation on a field within a test class. +* `@ExtendWith` annotations can now also be repeated when used directly on fields and + parameters. * All `@...Source` annotations of parameterized tests can now also be repeated when used as meta annotations. - [[release-notes-5.11.3-junit-jupiter-deprecations-and-breaking-changes]] ==== Deprecations and Breaking Changes diff --git a/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/Extensions.java b/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/Extensions.java index 652c606d63cb..3607def6d0aa 100644 --- a/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/Extensions.java +++ b/junit-jupiter-api/src/main/java/org/junit/jupiter/api/extension/Extensions.java @@ -33,7 +33,7 @@ * @see ExtendWith * @see java.lang.annotation.Repeatable */ -@Target({ ElementType.TYPE, ElementType.METHOD }) +@Target({ ElementType.TYPE, ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER }) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited diff --git a/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/ExtensionRegistrationViaParametersAndFieldsTests.java b/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/ExtensionRegistrationViaParametersAndFieldsTests.java index 9e934c3a9875..a9f04addddd6 100644 --- a/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/ExtensionRegistrationViaParametersAndFieldsTests.java +++ b/jupiter-tests/src/test/java/org/junit/jupiter/engine/extension/ExtensionRegistrationViaParametersAndFieldsTests.java @@ -132,6 +132,12 @@ void testTemplateMethodParameter() { assertTestsSucceeded(TestTemplateMethodParameterTestCase.class, 2); } + @Test + void multipleRegistrationsViaParameter(@TrackLogRecords LogRecordListener listener) { + assertOneTestSucceeded(MultipleRegistrationsViaParameterTestCase.class); + assertThat(getRegisteredLocalExtensions(listener)).containsExactly("LongParameterResolver", "DummyExtension"); + } + @Test void staticField() { assertOneTestSucceeded(StaticFieldTestCase.class); @@ -147,9 +153,11 @@ void fieldsWithTestInstancePerClass() { assertOneTestSucceeded(TestInstancePerClassFieldTestCase.class); } - @Test - void multipleRegistrationsViaField(@TrackLogRecords LogRecordListener listener) { - assertOneTestSucceeded(MultipleRegistrationsViaFieldTestCase.class); + @ParameterizedTest + @ValueSource(classes = { MultipleMixedRegistrationsViaFieldTestCase.class, + MultipleExtendWithRegistrationsViaFieldTestCase.class }) + void multipleRegistrationsViaField(Class testClass, @TrackLogRecords LogRecordListener listener) { + assertOneTestSucceeded(testClass); assertThat(getRegisteredLocalExtensions(listener)).containsExactly("LongParameterResolver", "DummyExtension"); } @@ -567,14 +575,37 @@ private static TestTemplateInvocationContext emptyTestTemplateInvocationContext( } } - static class MultipleRegistrationsViaFieldTestCase { + @ExtendWith(LongParameterResolver.class) + static class MultipleRegistrationsViaParameterTestCase { + + @Test + void test(@ExtendWith(DummyExtension.class) @ExtendWith(LongParameterResolver.class) Long number) { + assertThat(number).isEqualTo(42L); + } + } + + static class MultipleMixedRegistrationsViaFieldTestCase { @ExtendWith(LongParameterResolver.class) @RegisterExtension DummyExtension dummy = new DummyExtension(); @Test - void test() { + void test(Long number) { + assertThat(number).isEqualTo(42L); + } + } + + static class MultipleExtendWithRegistrationsViaFieldTestCase { + + @SuppressWarnings("unused") + @ExtendWith(LongParameterResolver.class) + @ExtendWith(DummyExtension.class) + Object field; + + @Test + void test(Long number) { + assertThat(number).isEqualTo(42L); } } diff --git a/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/ArchUnitTests.java b/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/ArchUnitTests.java index 3091293004dd..1ecbc4764582 100644 --- a/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/ArchUnitTests.java +++ b/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/ArchUnitTests.java @@ -17,7 +17,6 @@ import static com.tngtech.archunit.core.domain.JavaClass.Predicates.resideInAPackage; import static com.tngtech.archunit.core.domain.JavaClass.Predicates.resideInAnyPackage; import static com.tngtech.archunit.core.domain.JavaClass.Predicates.simpleName; -import static com.tngtech.archunit.core.domain.JavaClass.Predicates.type; import static com.tngtech.archunit.core.domain.JavaModifier.PUBLIC; import static com.tngtech.archunit.core.domain.properties.HasModifiers.Predicates.modifier; import static com.tngtech.archunit.core.domain.properties.HasName.Predicates.name; @@ -51,7 +50,6 @@ import com.tngtech.archunit.library.GeneralCodingRules; import org.apiguardian.api.API; -import org.junit.jupiter.api.extension.ExtendWith; @AnalyzeClasses(locations = ArchUnitTests.AllJars.class) class ArchUnitTests { @@ -72,7 +70,6 @@ class ArchUnitTests { .that(nameStartingWith("org.junit.")) // .and().areAnnotations() // .and().areAnnotatedWith(Repeatable.class) // - .and(are(not(type(ExtendWith.class)))) // to be resolved in https://github.com/junit-team/junit5/issues/4059 .should(haveContainerAnnotationWithSameRetentionPolicy()) // .andShould(haveContainerAnnotationWithSameTargetTypes());